Data analysis in Matlab - matlab

I have a time vector in Matlab which does not have consistent sampling time, ex. t = [0.1 0.2 0.3 0.4 0.5 0.6 0.7 1.3 1.4 1.5 1.6 1.7 1.8 1.9 2 2.9 3 3.1], I have another vector which is time based as a = [2 5 2 4 5 7 8 0 10 1 0 25 6 14 5 2 7 98], when I plot(t,a) there is straight line connecting the two points with larger sampling time, how can I remove these gaps where the sampling time is not consistent and it jumps to larger value? I know defining NaN between 0.7 and 1.3 and also 2 and 2.9 in t and also in a for the same interval might help, but how to distinguish if sampling time changes?

Maybe you can try the following codes, and here are two approaches that you can make it:
Approach 1: adding nan
clc;
clear;
close all;
t = [0.1 0.2 0.3 0.4 0.5 0.6 0.7 1.3 1.4 1.5 1.6 1.7 1.8 1.9 2 2.9 3 3.1]
a = [2 5 2 4 5 7 8 0 10 1 0 25 6 14 5 2 7 98]
dt = diff(t);
idx = find(dt > mode(dt));
tC = mat2cell(t',[idx(1),diff([idx,length(t)])]);
aC = mat2cell(a',[idx(1),diff([idx,length(t)])]);
nadd = dt(idx)/mode(dt);
T = [];
A = [];
for i = 1:length(nadd)
T = [T; tC{i};ones(int32(nadd(i)),1)*nan];
A = [A; aC{i};ones(int32(nadd(i)),1)*nan];
endfor
T = [T;tC{end}];
A = [A;aC{end}];
plot(T,A)
Approach 2: dividing vector by intervals
clc;
clear;
t = [0.1 0.2 0.3 0.4 0.5 0.6 0.7 1.3 1.4 1.5 1.6 1.7 1.8 1.9 2 2.9 3 3.1]
a = [2 5 2 4 5 7 8 0 10 1 0 25 6 14 5 2 7 98]
dt = diff(t);
idx = find(dt > mode(dt));
tC = mat2cell(t',[idx(1),diff([idx,length(t)])]);
aC = mat2cell(a',[idx(1),diff([idx,length(t)])]);
hold on;
arrayfun(#(k) plot(tC{k},aC{k}),1:(length(idx)+1));

Related

Interpolating matrices with 2 variables and 1 dependent value

I'm analyzing an induction motor, varying the frequency and absolute value of the stator current. Since the FEM-Tool only works with a current input, I need to vary the current over the frequency to obtain current-values of constant torque for each frequency.
To generate a mesh, I use 2 for-loops:
The outer loop sets the current.
The inner loop varies the frequency with said current, gets the machine's torque and finally, the matrices are appended adding the current stator-current, frequency and torque each in separate matrices. Plotted it looks like this:
Example of the plot using the raw data
For the plot I used smaller, more imprecise matrices and rather arbitrary values:
I_S = [ 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 ];
fre = [ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 ];
tor = [ 0 0.1 0.3 0.5 0.7 1 1.5 2 2.6 3.3 0 1.1 1.3 1.5 1.7 2 2.5 3 3.6 4.3 0 2.1 2.3 2.5 2.7 3 3.5 4 4.6 5.3 ];
While tor is shown as the colormap in the plot. Each matrix has a length of 30.
One simulation needs about 20-30 seconds. Thus, to get a precise mesh, the FEM-tool needs several hours to generate.
I would like to interpolate the spaces in between the known ones.
It seems that either the way of creating the matrices is the problem or the interp*...-functions of Octave/MATLAB simply don't work for this kind of interpolation.
Is there a way to achieve a mesh/grid-like interpolation from this type of matrices? I found many examples with x,y as variables and z as a math-function but rarely 3 linear/non-linear matrices.
Your data need to be in a meshgrid form, that is 2D:
// Known data
current = [0:2];
frequency = [0:9];
[current2D, frequency2D] = meshgrid(current,frequency);
torque2D = [ 0 0.1 0.3; 0.5 0.7 1; 1.5 2 2.6; 3.3 0 1.1; 1.3 1.5 1.7; 2 2.5 3; 3.6 4.3 0; 2.1 2.3 2.5; 2.7 3 3.5; 4 4.6 5.3 ];
// Interpolated data
currentToInterpolate = [0.5 1.5];
frequncyToInterpolate = [0.5 : 8.5];
[currentToInterpolate2D, frequencyToInterpolate2D] = meshgrid(currentToInterpolate,frequncyToInterpolate);
interpolatedTorque2D = interp2(current2D,frequency2D,torque2D,currentToInterpolate2D,frequencyToInterpolate2D);

Map 1 to 12 to set of decimals

I have a vector m which ranges from 1 to 12 randomly.
3 12 12 7 10 3 6 12 10 12
I have a conversion table
1 2 3 4 5 6 7 8 9 10 11 12
0.6 0.7 1.8 0.9 0.5 1.6 0.9 1.5 1.8 0.8 0.9 0.5
That means if m(1)==3, I want to change m(1) to be 1.8.
if m(2)==12, I want to change m(2) to be 0.5.
May I know what it the quickest way to do this conversion? Thank you.
This can be done with indexing
conversion_table = [0.6 0.7 1.8 0.9 0.5 1.6 0.9 1.5 1.8 0.8 0.9 0.5];
m = [3 12 12 7 10 3 6 12 10 12];
m = conversion_table(m)

Read more than 3000 txt files by using loop

I have more than 3000 Data txt files. I create the name for these file according to special rate by this code
clc;
clear all;
close all;
%%
h=[1];
k_plus =[0.1 0.2 0.4 0.7 1 1.1 1.2 1.5 1.7 2 2.5 3 3.5 4 5];
K_minus_T =[1e-6 0.1 0.2 0.4 0.7 1 1.1 1.2 1.5 1.7 2 2.5 3 3.5 4 5];
K_minus_D = [1e-6 0.1 0.2 0.4 0.7 1 1.1 1.2 1.5 1.7 2 2.5 3 3.5 4 5];
sets = {k_plus, K_minus_T, K_minus_D,h};
[x,y,z r] = ndgrid(sets{:});
cartProd = [x(:) y(:) z(:) r(:)];
nFiles = size(cartProd,1);
filename{nFiles,1}=[];
for i=1:nFiles
filename{i} = ['MTN100_' ...
'k+' num2str(cartProd(i,1)) '_' ...
'k-T_' num2str(cartProd(i,2)) '_' ...
'k-D' num2str(cartProd(i,3)) '_' ...
'h' num2str(cartProd(i,4)) '_' ...
'GTP0.txt'];
end
Now I want to read each file in the loop and do some processing. I tried to use textscan and textread but It is not work.
h=[1];
k_plus =[0.1 0.2 0.4 0.7 1 1.1 1.2 1.5 1.7 2 2.5 3 3.5 4 5];
K_minus_T =[1e-6 0.1 0.2 0.4 0.7 1 1.1 1.2 1.5 1.7 2 2.5 3 3.5 4 5];
K_minus_D = [1e-6 0.1 0.2 0.4 0.7 1 1.1 1.2 1.5 1.7 2 2.5 3 3.5 4 5];
sets = {k_plus, K_minus_T, K_minus_D,h};
[x,y,z r] = ndgrid(sets{:});
cartProd = [x(:) y(:) z(:) r(:)];
nFiles = size(cartProd,1);
filename{nFiles,1}=[];
for i=1:nFiles
filename{i} = ['MTN100_' ...
'k+' num2str(cartProd(i,1)) '_' ...
'k-T_' num2str(cartProd(i,2)) '_' ...
'k-D' num2str(cartProd(i,3)) '_' ...
'h' num2str(cartProd(i,4)) '_' ...
'GTP0.txt'];
file1=fopen(filename{i},'r')
C=textscan(filename{i},'%u');
t1 = C(1,:);
d1 = C(3,:);
plot(t1, d1, 'b*-', 'LineWidth', 2, 'MarkerSize', 3);
fclose(filename{i});
end
I am mainly using C++ and not really familiar with how to do the similar things in MATLAB.Any help would be greatly appreciated. I will be grateful to you.
I'm not sure what the issue is that you're experiencing, but I spotted a couple of errors in your code. fopen returns a file ID, it's this file ID that you should then pass into textscan and fclose, not the file name. The second argument to textscan is the format specifier of a single row of the data that you're scanning. You mentioned in the comments that there are 7 real values, I've set the formatspec to '%f%f%f%f%f%f%f' which will treat the values as doubles. If your values are delimited with anything other than whitespace you'll need to add delimiter information to the textscan call.
h=[1];
k_plus =[0.1 0.2 0.4 0.7 1 1.1 1.2 1.5 1.7 2 2.5 3 3.5 4 5];
K_minus_T =[1e-6 0.1 0.2 0.4 0.7 1 1.1 1.2 1.5 1.7 2 2.5 3 3.5 4 5];
K_minus_D = [1e-6 0.1 0.2 0.4 0.7 1 1.1 1.2 1.5 1.7 2 2.5 3 3.5 4 5];
sets = {k_plus, K_minus_T, K_minus_D,h};
[x,y,z r] = ndgrid(sets{:});
cartProd = [x(:) y(:) z(:) r(:)];
nFiles = size(cartProd,1);
filename{nFiles,1}=[];
for i=1:nFiles
filename{i} = ['MTN100_' ...
'k+' num2str(cartProd(i,1)) '_' ...
'k-T_' num2str(cartProd(i,2)) '_' ...
'k-D' num2str(cartProd(i,3)) '_' ...
'h' num2str(cartProd(i,4)) '_' ...
'GTP0.txt'];
file1=fopen(filename{i},'r')
C=textscan(file1,'%f%f%f%f%f%f%f');
fclose(file1);
t1 = C(1,:);
d1 = C(3,:);
plot(t1, d1, 'b*-', 'LineWidth', 2, 'MarkerSize', 3);
end

scale part of an axis in matlab

I have the following image which I want to have the depth axis range like below :
(10 9.5 9 8.5 8 7.5 7 6 5 3 2 1 0.9 0.8 0.7 0.6 0.5 0.4 0.3 0.2 0.1 0) to show the data between depth 1 and 0 in larger scale, and I have the following code
depths = [10 5 1 0.5 0; 10 5 1 0.5 0] % these are the real depths in meter
contourf(points,depths,RFU15102013_BloomAsMainPoint);
set(gca, 'XTick', points(1) : points(2), 'XTickLabel',{ 'LSB1', 'LSB2'});
ylabel('Depth(m)');
xlabel('Points');
title('Date: 15.10.2013');
this is the image :
how can I do that?
EDIT1
Real Data:
RFU15102013_BloomAsMainPoint = [ 2.71 1.23 1.30 1.20 14.37 ; 2.51 1.36 1.01 1.24 1.15];
points = [1 1 1 1 1; 2 2 2 2 2 ];
depths = [10 5 1 0.5 0; 10 5 1 0.5 0];
As most of a data changes around zero it could be enough to change scaling of Y axis. Here is an example
close all; clear all;
z = [ 2.71 1.23 1.30 1.20 14.37 ; 2.51 1.36 1.01 1.24 1.15];
x = repmat([1; 2], 1, 5);
y = repmat([10 5 1 0.5 0], 2, 1);
% plotting with equally spaced y-s
h = subplot(1,2,1);
contourf(x,y,z);
y2 = log(y + 0.25);
yTicks = linspace(min(y2(1,:)), max(y2(1,:)), 10);
% plotting with logarithmically spaced y-s
h = subplot(1,2,2)
contourf(x,y2,z);
set(h,'YTick', yTicks)
set(h,'YTickLabel', exp(yTicks) - 0.25);
print('-dpng','scaling.png')
The result
This way any monotonic continuous function for axis scaling can be applied.
You could use UIMAGE - UIMAGESC from the mathworks file exchange and set the y values to emphaisize points in 1 to 0 range.

find and replace zeros with a function in matlab

Once again, sorry if this has been asked before and if its too specific but I'm very stuck and can't quite find a solution.
I have a matrix of say 3 members of a structure called 2, 4 and 16 (in column 1) that have values along their relative distance e.g. member 2 has values at the start, 0m, then at 0.5m then the end of its length 1.5m, where member 4 starts at 0m etc. So that my matrix looks like this:
2 0 125
2 0.5 25
2 1.5 365
4 0 25
4 0.6 57
16 0 354
16 0.2 95
16 0.8 2
and I want to create a matrix that has the overall distance along all the members 2, 4 and 16 combined:
2 0 125
2 0.5 25
2 1.5 365
4 1.5 25
4 2.1 57
16 2.1 354
16 2.3 95
16 3.1 2
is there any way to do this in matlab? Like possibly locating the first zero and adding the value above it to all the rest of the values below then find the next zero value and so on?
Please tell me if this isn't clear, I realise it's a bit confusing but not too sure how to explain it better!
I came up with the following:
idx = find(diff(M(:,1)));
v = zeros(size(M,1),1);
v(idx+1) = M(idx,2);
M(:,2) = M(:,2) + cumsum(v);
The result:
M =
2 0 125
2 0.5 25
2 1.5 365
4 1.5 25
4 2.1 57
16 2.1 354
16 2.3 95
16 2.9 2
Note the last value in the second column disagrees with what you described (2.9 vs 3.1). Either you had a typo, or I'm still not getting it...
data = [2 0 125;
2 0.5 25;
2 1.5 365;
4 0 25;
4 0.6 57;
16 0 354;
16 0.2 95;
16 0.8 2];
idx0 = find(data(:,2)==0);
idx0 = idx0(2:end); %ignore first zero of first member, doesn't need an offset
offset = data(idx0-1,2);
N = size(data,1);
for ii=1:numel(idx0)
idxs = 1:N>=idx0(ii);
data(idxs,2) = data(idxs,2) + offset(ii);
end