Interpolating matrices with 2 variables and 1 dependent value - matlab

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);

Related

Resampling of an audio signal with new time array

I am asking an upgraded and more focused version of my query as I think I remained unable to explain properly in my last query.
I want to down sample my signal based on new time array.
I have time array and sample array.
t = [0 2 3 7 8 9 10 11 12 17 18 19 20];
A = [0 0 1 2 3 5.2 0 -1.4 0 2 2.7 2 2.3];
New time array is:
Tx = 1:4:25;
I am using interpolation proposed by Andrei Davydov on stackoverflow but I think I am at fault some point.
Can someone point me out where I am at fault? Thanks a lot in advance.
If the value of A is same at Tx as w.r.t (t)then use that value and if no value is found interpolate value and assign that value to new time .
Example Code:
t = [0 2 3 7 8 9 10 11 12 17 18 19 20 ];
A = [0 0 1 2 3 5.2 0 -1.4 0 2 2.7 2 2.3 ];
plot(t,A)
Tx = 1:4:25;
B = interp1(t,A,Tx); %re-make example data to have decimal points on the x-axis
y = resample(B, 1, 2);
T = 0.05;
Ty = T / (1 / 2);
ty = (0:length(y)-1)*Ty;
figure
plot(Tx,B,'b')
hold on
plot(ty,y,'r')
plot(t,A,'g')
hold off
Link to my previous question is attached here.
Resampling of time signal in MATLAB
Note :
This is now exactly what i want so this is more clear and mature.
I am using MATLAB version 2012b so please provide me solution w.r.t that as there are few Matlab build in command which don't work in 2012b.
The main Your problem - you try to extrapolate, as original time ends at 20, but Yours ends at 25. Try this code:
clc
t = [0 2 3 7 8 9 10 11 12 17 18 19 20 ];
A = [0 0 1 2 3 5.2 0 -1.4 0 2 2.7 2 2.3 ];
Tx = 1:4:25; % Are you sure you want to extrapolate?
% max(Tx1)>max(t)
% This variant is WITHOUT extrapolation
B = interp1(t,A,Tx);
% This variant is WITH extrapolation and WHOLE time-series interpolated
% cubically
extrapBcub=interp1(t,A,Tx,'pcchip');
% If you want to have linear (default) interpolation, but cubic
% extrapolation then
extrapBlin=[B(~isnan(B)), extrapBcub(isnan(B))];
It gives the following figure:
f=figure('Position',[50 50 1500 800])
h1=subplot(1,2,1);
hold all
h(1)=plot(t,A,'-ok','LineWidth',3)
h(2)=plot(Tx,B,'-ob','LineWidth',9)
h(3)=plot(Tx,extrapBcub,':or','LineWidth',7)
h(4)=plot(Tx,extrapBlin,'-og','LineWidth',3)
xlabel('time')
ylabel('signal')
set(gca,'Box','off','Color','none','FontSize',14,'LineWidth',2)
legend({'Original data','No extrapolation','Cubic all',...
'Linear interpolation+cubic extrapolation'},'Location','SouthOutside',...
'FontSize',22)
legend boxoff
h2=subplot(1,2,2);
hold all
h3 = copyobj(h(end:-1:1), h2) % copy plots just for scaling
ylim([-2 6])
xlabel('time')
ylabel('signal')
set(gca,'Box','off','Color','none','FontSize',14,'LineWidth',2)

MATLAB - hierarchy clustering upon two data sets

I have two data sets (characteristic_1, characteristic_2) corresponding to five objects (each). Every object has tree attributes, att1, att2, att3.
So for characteristic_1, the matrix is:
d= [ 1 1 0; 1.1 1 2; 0.9 0.2 1; 1.2 0.8 1.3; 1 1 1]
and for characteristic_2, the matrix is:
e= [ 1.1 1 0; 1 1 2; 0.7 0.2 1.1; 1.2 0.8 1.3; 1.3 1 1]
I want to use the hierarchy method (i.e. single linkage), in order to cluster characteristic_1 & 2 (between them). The 5 objects, as well as the 3 attributes, are common in the two characteristics.
Thanks in advance.

Find Value at a given Orientation in Matrix

In Matlab I've matrix where, in a previous stage of my code, an specific element was chosen. From this point of the matrix I would like to find a maximum, not just the maximum value between all its surounding neighbours for a given radius, but the maximum value at a given angle of orientation. Let me explain this with an example:
This is matrix A:
A =
0 1 1 1 0 0 9 1 0
0 2 2 4 3 2 8 1 0
0 2 2 3 3 2 2 1 0
0 1 1 3 2 2 2 1 0
0 8 2 3 3 2 7 2 1
0 1 1 2 3 2 3 2 1
The element chosen in the first stage is the 4 in A(2,4), and the next element should be the maximum value with, for example, a 315 degrees angle of orientation, that is the 7 in A(5,7).
What I've done is, depending on the angle, subdivide matrix A in different quadrants and make a new matrix (an A's submatrix) with only the values of that quadrant.
So, for this example, the submatrix will be A's 4th quadrant:
q_A =
4 3 2 8 1 0
3 3 2 2 1 0
3 2 2 2 1 0
3 3 2 7 2 1
2 3 2 3 2 1
And now, here is my question, how can I extract the 7?
The only thing I've been able to do (and it works) is to find all the values over a threshold value and then calculate how those points are orientated. Then, saving all the values that have a similar orientation to the given one (315 degrees in this example) and finally finding the maximum among them. It works but I guess there could be a much faster and "cleaner" solution.
This is my theory, but I don't have the image processing toolbox to test it. Maybe someone who does can comment?
%make (r,c) the center by padding with zeros
if r > size(A,1)/2
At = padarray(A, [size(A,1) - r], 0, 'pre');
else
At = padarray(A, [r-1], 0 'post');
if c > size(A,2)/2
At = padarray(At, [size(A,2) - c], 0, 'pre');
else
At = padarray(At, [c-1], 0 'post');
%rotate by your angle (maybe this should be -angle or else 360-angle or 2*pi-angle, I'm not sure
Ar = imrotate(At,angle, 'nearest', 'loose'); %though I think nearest and loose are defaults
%find the max
max(Ar(size(Ar,1)/2, size(Ar,2)/2:end); %Obviously you must adjust this to handle the case of odd dimension sizes.
Also depending on your array requirements, padding with -inf might be better than 0
The following is a relatively inexpensive solution to the problem, although I found wrapping my head around the matrix coordinate system a real pain, and there is probably room to tidy it up somewhat. It simply traces all matrix entries along a line around the starting point at the supplied angle (all coordinates and angles are of course based on matrix index units):
A = [ 0 1 1 1 0 0 9 1 0
0 2 2 4 3 2 8 1 0
0 2 2 3 3 2 2 1 0
0 1 1 3 2 2 2 1 0
0 8 2 3 3 2 7 2 1
0 1 1 2 3 2 3 2 1 ];
alph = 315;
r = 2;
c = 4;
% generate a line through point (r,c) with angle alph
[nr nc] = size(A);
x = [1:0.1:nc]; % overkill
m = tan(alph);
b = r-m*c;
y = m*x + b;
crd = unique(round([y(:) x(:)]),'rows');
iok = find((crd(:,1)>0) & (crd(:,1)<=nr) & (crd(:,2)>0) & (crd(:,2)<=nc));
crd = crd(iok,:);
indx=sub2ind([nr,nc],crd(:,1),crd(:,2));
% find max and position of max
[val iv]=max(A(indx)); % <-- val is the value of the max
crd(iv,:) % <-- matrix coordinates (row, column) of max value
Result:
val =
7
iv =
8
ans =
5 7

Combine data matrices of different frequencies

In MATLAB, how could I combine two matrices of data measured at different frequencies such that the result is indexed at the higher frequency? Since the data measured at the lower frequency will have many unknown values in the result, I would like to replace them with the last known value in the matrix. There is a lot of data so a vectorized solution would be preferred. I've added some sample data below.
Given:
index1 data1 index2 data2
1 2.1 2 30.5
2 3.3 6 32.0
3 3.5 9 35.0
4 3.9 13 35.5
5 4.5 17 34.5
6 5.0 20 37.0
7 5.2 ... ...
8 5.7
9 6.8
10 7.9
... ...
Result:
index1 data1 data2
1 2.1 NaN
2 3.3 30.5
3 3.5 30.5
4 3.9 30.5
5 4.5 30.5
6 5.0 32.0
7 5.2 32.0
8 5.7 32.0
9 6.8 35.0
10 7.9 35.0
... ... ...
EDIT:
I think the following post is close to what I need, but I'm not sure how to transform the solution to fit my problem.
http://www.mathworks.com/matlabcentral/newsreader/view_thread/260139
EDIT (Several Months Later):
I've recently come across this excellent little function that I think may be of use to anyone who lands on this post:
function yi = interpLast(x,y,xi)
%INTERPLAST Interpolates the input data to the last known value.
% Note the index data should be input in ASCENDING order.
inds = arrayfun(#findinds, xi);
yi = y(inds);
function ind = findinds(val)
ind = find(x<=val,1,'last');
if isempty(ind)
ind = 1;
end
end
end
Credit goes here: http://www.mathworks.com/support/solutions/en/data/1-48KETY/index.html?product=SL&solution=1-48KETY
The problem is one of run length decoding. See section 15.5.2 of Matlab array manipulation tips and tricks (which is an eye-opening read for any Matlab enthusiast).
Here's using the method with your example (I'm using octave but the code is identical for Matlab):
octave:33> a=[2,30.5;6,32;9,35;13,35.5;17,34.5;20,37]
a =
2.0000 30.5000
6.0000 32.0000
9.0000 35.0000
13.0000 35.5000
17.0000 34.5000
20.0000 37.0000
octave:34> i=a(:,1)-1
i =
1
5
8
12
16
19
octave:35> j=zeros(1,i(end))
j =
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
octave:36> j(i(1:end-1)+1)=1
j =
0 1 0 0 0 1 0 0 1 0 0 0 1 0 0 0 1 0 0
octave:37> j(1)=1
j =
1 1 0 0 0 1 0 0 1 0 0 0 1 0 0 0 1 0 0
octave:38> val=a(:,2)
val =
30.500
32.000
35.000
35.500
34.500
37.000
octave:39> x=val(cumsum(j))
x =
30.500
32.000
32.000
32.000
32.000
35.000
35.000
35.000
35.500
35.500
35.500
35.500
34.500
34.500
34.500
34.500
37.000
37.000
37.000
And pad the beginning with NaN as needed.
I recently had the same problem as you: I had data, measured by different systems, which had to be synchronized and processed.
My solution consisted of putting the measurement data and time information (frequency, time at start of measurements) in a class object. Then I implemented a multiplication, addition, etc. method for that class that automatically took care of all the necessary things, being:
upsampling the lower frequency signal (with linear interpolation (interp1)
shifting one of the signals, so the data lines up in time
cutting off the non-overlapping data set at beginning and end (with two different systems you never start or stop measuring at the same time, so there is some excess data)
actually performing the multiplication
returning the result as a new class object
Next to that there were other functions of which you can guess what they do: plot, lpf, mean, getTimeAtIndex, getIndexAtTime, ...
This allowed me to simply do
signalsLabview = importLabViewSignals(LabViewData);
signalsMatlab = importMatlabSignals(MatlabData, 100); %hz
hydrPower = signalsLabview.flow * signalsMatlab.pressure;
plot(hydrPower);
or things like that. If you have a lot of these signals on which you have to do some math, this really helps and results in clear code. Otherwise you have a lot of general code just for doing the syncing, shifting, trimming around each operation. Also for quickly checking things it's easy.
If you have to do this things a lot, I think it's definitely worth investing some time in it to build a proper framework.
Unfortunately I don't think I can disclose this code (IP and such), but it wasn't rocket science.

A combination of hist and sum:is there a function for that?

Lets say we have following vector:
data=a=[2.3 3.2 4.1 6.2 7.3 6.4 5.5 4.3 3.2 2.6 1.7 3.4 4.5 5.7 6.8];
If we count the numbers only by using the hist-function, we get something like that:
[n xout]=hist(a,[1:1:max(a)])
n =
0 0 2 4 3 1 3 2
xout =
0 1 2 3 4 5 6 7
What i now want to make is to sum each element of a bin:
xout =
0 1 2 3 4 5 6 7
n =
0 0 2 4 3 1 3 2
binsum =
0 0 4 12.4 etc.
for the third bin for example i have n(3)=2 values that are between 1,5 and 2,5 (size of a bin):1.7 and 2.3 -> 1.7+2.3=4 -> binsum(3)=4
for the fourth bin i have n(4)=4 values that are between 2,5 and 3,5:3.2+3.2+3.4+2.6=12.4-> binsum(4)=12.4 etc.
is there a simple function which do this job?
If your histogram bins are defined by the array minBin:binWidth:maxBin, then you can find the indices of the bins, and then sum up the data like this:
minBin = 1;
binWidth = 1;
maxBin = 7;
data=[2.3 3.2 4.1 6.2 7.3 6.4 5.5 4.3 3.2 2.6 1.7 3.4 4.5 5.7 6.8];
%# to create index: First, take care of out-of-range data points
tmp = max(min( data, maxBin),minBin);
%# then, subtract minimum, divide by step, round: this is the binIdx
%# add 1 so that we don't start counting at 0
idx = round( (tmp-minBin)/binWidth ) +1;
%# now we can use accumarray to sum up the data
binSum = accumarray(idx(:),data(:),[floor((maxBin-minBin)/binWidth)+1, 1], #sum, 0)
binSum =
0
4.0000
12.4000
8.4000
4.5000
23.8000
14.1000
Note that I don't get two zeros first, because I use the bins you used as input to hist, not the ones you apparently used to generate the outputs. Also, you can get the counts by replacing data by ones(length(data),1).