matlab functions about sine curve - matlab

I have a question about matlab programming about sine curve.
The question is as below:
Consider the definition: function [s1, s2, sums] = sines(pts,amp,f1,f2). The input, pts, is an integer, but amp, f1, and f2 and are not necessarily integers. Output argument s1 is a row vector whose length (number of elements) equals pts. The elements of s1 are the values of the sine function when it is given equally spaced arguments that start at zero and extend through f1 periods of the sine. (Note that we ask for full periods, so if f1 is an integer, both the first and the last element of s1 will be 0 other than a very small rounding error.) The amplitude of the sine wave equals amp. The vector s2 is the same as s1 except that s2 contains f2 periods. The vector sums is the sum of s1 and s2. If f2 is omitted, then it should be set to a value that is 5% greater than f1. If f1 is omitted also, then it should be set to 100. If amp is not provided, then it should default to 1. Finally, if pts is omitted as well, then it should be set to 1000.
Here is what I am confused: how to define step length pts. I used the following method but it fails to work. Please help me to fix it.
function [s1, s2, sums] = sines(pts,amp,f1,f2)
.................
t = linspace(0, 1, pts);
s1=amp*sin(2*pi*f1*t);
s2=amp*sin(2*pi*f2*t);
Thanks.

As far as the part of the code you are confused this should work for you:
n=pts-1
t=0:n;
s1=amp*sin(2*pi*f1/n*t);
s2=amp*sin(2*pi*f2/n*t);
then you sum s1+s2. You still need to handle the missing input if any.

Related

Zero crossings around mean

I am working on developing a suite classifiers for EEG signals and I will be needing a zero-crossings around mean function, defined in the following manner:
Ideally if I have some vector with a range of values representing a sinusoid or any time varying signal, I will want to return a vector of Booleans of the same size as the vector saying if that particular value is a mean crossing. I have the following Matlab implementation:
ZX = #(x) sum(((x - mean(x)>0) & (x - mean(x)<0)) | ((x - mean(x)<0) & (x - mean(x)>0)));
Testing it on toy data:
[0 4 -6 9 -20 -5]
Yields:
0
EDIT:
Yet I believe it should return:
3
What am I missing here?
An expression like:
((x-m)>0) & ((x-m)<0)
is always going to return a vector of all zeros because no individual element of x is both greater and less than zero. You need to take into account the subscripts on the xs in the definition of ZX:
((x(1:end-1)-m)>0) & ((x(2:end)-m)<0)
You can use the findpeaks function on -abs(x), where x is your original data, to find the peak locations. This would give you the zero crossings in general for continuous signals which do not have zero as an actual maximum of the signal.
t = 0:0.01:10;
x = sin(pi*t);
plot(t,x)
grid
y = -abs(x);
[P,L] = findpeaks(y,t);
hold on
plot(L,P,'*')
A simple solution is to use movprod, and count the products which are negative, i.e.,
cnt = sum(sign(movprod(x-mean(x),2))<0);
With your toy example, you will get cnt = 3.

multipoint boundary value ode with varying coefficients in matlab

I have a second order differential equation given as:
d²u/dz²=a+bu, where a and b are constants that vary in different intervals and z∈[0,Zn]
Intervals are given as I1:z∈[0,Z1), I2:z∈[Z1, Z2), ..., I(n):z∈[Z(n-1), Z(n)] and {a,b} constants varies as {a1,b1} in I1, {a2,b2} in I2,...,{an,bn} in I(n).
Boundary condition is given as u(z=0)=U0, u(z=Zn)=Umax.
A continuous graph of u vs z is required.
I thought of using bvp5c in matlab but bvp5c can solve multipoint boundary value problems where a = a0 < a1 < a2 < ... < an = b in the interval [a,b]. The points a1,a2, ... ,an–1 represent interfaces that divide [a,b] into regions. The problem is my constants(a,b in above ode) is also varying in different intervals.
You can do it. If you read the bvp5c docs, you will see that it takes a function handle (odefun) which takes the z, and u arguments. Simply return the correct value for the RHS based on value of the argument z. Note that you have to convert your 2nd order equation to a 1st order one.
du/dz = v
dv/dz = a(z) + b(z)u
You need to return the vector [v, a(z) + b(z)u] from the two arguments z and [u,v] that your odefun will be called with.

calculate conservative interpolation of two vectors in matlab

G'day
Firstly, apologies for poor wording - I'm at a bit of a loss of how to describe this problem. I'm trying to calculate the conservative interpolation between two different vertical coordinate systems.
I have a vector of ocean transport values Ts, that describe the amount of transport at different depth values S. These depths are unevenly spaced (and size(S) is equal to size(Ts)+1 as the values in S are the depths at the top and bottom over which the transport value applies). I want to interpolate(/project?) this onto a vector of regularly spaced depths Z, where each new transport value Tz is formed from the values of Ts but weighted by the amount of overlap.
I've drawn a picture of what I mean (sorry for the bad quality webcam picture) I want to go from Ts1,Ts2.Ts3...TsN (bottom lines) to Tz1,Tz2,...TzN (top lines). The locations in the x direction for these are s0,s1,s2,...sN and z0,z1,z2,...zN. An example of the 'weighted overlap' would be:
Tz1 = a/(s1-s0) Ts1 + b/(s2-s1) Ts2 + c/(s3-s2) Ts3
where a, b and c are shown in the image as the length of overlap.
Some more details:
Example of z and s follow:
z = 0:5:720;
s = [222.69;...
223.74
225.67
228.53
232.39
237.35
243.56
251.17
260.41
271.5
284.73
300.42
318.9
340.54
365.69
394.69
427.78
465.11
506.62
551.98
600.54
651.2];
Note that I'm free to define z, but not s. Typically, z will be bigger than s (i.e. the smallest value in z will be smaller than in s, while the largest value in z will be larger than in s).
Help or tips greatly appreciated. Cheers,
Dave
I don't think there is an easy solution, as stated in the comments. I'll give it a go though :
One hypothesis first : We assume z0>s0 in order for your problem to be defined.
The idea (for your example) would be to get to the array below :
1 (s1-z0) s1-s0 Ts1
1 (s2-s1) s2-s1 Ts2
1 (z1-s2) s3-s2 Ts3
2 (s3-z1) s3-s2 Ts3
2 (z2-s3) s4-s3 Ts4
3 (z3-z2) s4-s3 Ts4
......
Then we would be able to compute, for each row : column1*column3/column2 and then use accumarray to sum the results with respect to the indexes in the first column.
Now the hardest part is to get this array :
Suppose you have :
A Nx1 vectors Ts
2 (N+1)x1 vectors s and z, with z(1)>s(1).
Vectsz=sort([s(2:end);z]); % Sorted vector of s and z values
In your case this vector should look like :
z0
s1
s2
z1
s3
z2
z3
...
The first column will serve as a subscript to apply accumarray, so we'll want it to increase each time there is a z value in our vector Vectsz
First=interp1(z,1:length(z),Vectsz,'previous');
Second=[diff(Vectsz);0]; % Padded with a 0 to keep the right size
Temp=diff(s);
Third=interp1(s(1:end-1),Temp,Vectsz,'previous');
This will just repeat the diff value everytime you have a z value in your vector Vectsz.
The last column is built exactly like the third one
Fourth=interp1(s(1:end-1),Ts,Vectsz,'previous');
Now that the array is built, a call to accumarray is enough to get the final result :
Res=accumarray(First,Second.*Fourth./Third);
EDIT : There is actually no need for the use of interp1 with the previous option :
Vectsz=sort([s(2:end);z]);
First=cumsum(ismember(Vectsz,z));
Second=[diff(Vectsz);0];
idx=cumsum(ismember(Vectsz,s(2:end)))+1;
Diffs=[diff(s);0];
Third=Diffs(idx);
Fourth=Ts(idx);
Res=accumarray(First,Second.*Fourth./Third);

determine the frequency of a number if a simulation

I have the following function:
I have to generate 2000 random numbers from this function and then make a histogram.
then I have to determine how many of them is greater that 2 with P(X>2).
this is my function:
%function [ output_args ] = Weibullverdeling( X )
%UNTITLED Summary of this function goes here
% Detailed explanation goes here
for i=1:2000
% x= rand*1000;
%x=ceil(x);
x=i;
Y(i) = 3*(log(x))^(6/5);
X(i)=x;
end
plot(X,Y)
and it gives me the following image:
how can I possibly make it to tell me how many values Do i Have more than 2?
Very simple:
>> Y_greater_than_2 = Y(Y>2);
>> size(Y_greater_than_2)
ans =
1 1998
So that's 1998 values out of 2000 that are greater than 2.
EDIT
If you want to find the values between two other values, say between 1 and 4, you need to do something like:
>> Y_between = Y(Y>=1 & Y<=4);
>> size(Y_between)
ans =
1 2
This is what I think:
for i=1:2000
x=rand(1);
Y(i) = 3*(log(x))^(6/5);
X(i)=x;
end
plot(X,Y)
U is a uniform random variable from which you can get the X. So you need to use rand function in MATLAB.
After which you implement:
size(Y(Y>2),2);
You can implement the code directly (here k is your root, n is number of data points, y is the highest number of distribution, x is smallest number of distribution and lambda the lambda in your equation):
X=(log(x+rand(1,n).*(y-x)).*lambda).^(1/k);
result=numel(X(X>2));
Lets split it and explain it detailed:
You want the k-th root of a number:
number.^(1/k)
you want the natural logarithmic of a number:
log(number)
you want to multiply sth.:
numberA.*numberB
you want to get lets say 1000 random numbers between x and y:
(x+rand(1,1000).*(y-x))
you want to combine all of that:
x= lower_bound;
y= upper_bound;
n= No_Of_data;
lambda=wavelength; %my guess
k= No_of_the_root;
X=(log(x+rand(1,n).*(y-x)).*lambda).^(1/k);
So you just have to insert your x,y,n,lambda and k
and then check
bigger_2 = X(X>2);
which would return only the values bigger than 2 and if you want the number of elements bigger than 2
No_bigger_2=numel(bigger_2);
I'm going to go with the assumption that what you've presented is supposed to be a random variate generation algorithm based on inversion, and that you want real-valued (not complex) solutions so you've omitted a negative sign on the logarithm. If those assumptions are correct, there's no need to simulate to get your answer.
Under the stated assumptions, your formula is the inverse of the complementary cumulative distribution function (CCDF). It's complementary because smaller values of U give larger values of X, and vice-versa. Solve the (corrected) formula for U. Using the values from your Matlab implementation:
X = 3 * (-log(U))^(6/5)
X / 3 = (-log(U))^(6/5)
-log(U) = (X / 3)^(5/6)
U = exp(-((X / 3)^(5/6)))
Since this is the CCDF, plugging in a value for X gives the probability (or proportion) of outcomes greater than X. Solving for X=2 yields 0.49, i.e., 49% of your outcomes should be greater than 2.
Make suitable adjustments if lambda is inside the radical, but the algebra leading to solution is similar. Unless I messed up my arithmetic, the proportion would then be 55.22%.
If you still are required to simulate this, knowing the analytical answer should help you confirm the correctness of your simulation.

Finding the average number of consecutive same value elements in matlab

I have a question that I couldn't solve by myself, and search results have also not been what I am looking for (unless I missed one that explains it all, in which case I apologize!)
I have a system that can be in three states, S = S1, S2 and S3. It can change between these three states with a certain probability: From S1 to S2 with P1, S2 to S1 with P2, S2 to S3 with P3 and S3 to S2 with P4. However, to make things simple, I'll begin with P1 = P2 = P3 = P4 = P.
Now I have a dataset, an array of 1000000 values which correspond to these specific states. So S1 means a 1 in the array, S2 means 0.5 and S3 means 0.
So now I want to find out how long the average 'string' of consecutive 1's, or 0.5's, or 0's is in my array. As it is simply a binomial process, (change state with p = P), I should in principle be able to extract P from this information. Although I'm not sure how yet, as I can't simply fit the distribution of 'string lengths' to the binomial distribution, can I?
In any case, a good place to start would be to be able to extract the length of 'strings' of consecutive equal values. Could anyone point me in a direction for where to start?
Edit:
I see that fitdist could fit the 'string lengths' to the binomial distribution. So now I simply want to find how to create an array that contains the 'string lengths' for consecutive 1's, 0.5's and 0's.
Edit 2: It seems that Series of consecutive numbers (different lengths) might be doing exactly what I want. I'll have a quick look at it, and if so I'll delete the post. I apologize!
You could do something as simple as using a derivative. This will identify when there is a change in the sequence. Anywhere the derivative returns something other than 0, this indicates a change. Find what index those changes happen, and then you can find the differences between these indices to get the lengths. Here is some example code
% all just setup
a = 0*ones(1,randi([1,10]));
b = 1*ones(1,randi([1,10]));
c = 0.5*ones(1,randi([1,10]));
vals = {a,b,c};
len = 1e6;
temp = cell(1,len);
for i = 1:len
index = randi([1,3]);
temp{i} = vals{index};
end
mat = cell2mat(temp);
% code that actually does what you need
mat = [mat,nan];
seqLengths = diff([0,find(diff(mat) ~= 0)]);
Please note that the nan is added to the end of your vector so that you will get a vector of the same length at the end. nan is used because it is assumed that your vector will contain all valid numbers, if not, nan can be replaced with any value that does not match the last value in the matrix.
If it's really a binomial process, there is no need to count the average length. Count the transitions for each state:
y=sparse(x(1:end-1),x(2:end),ones(numel(x)-1,1))
And divide it by the total number of transitions:
z=y./sum(sum(y))