I am trying to round up the cx_n to its nearest number if the cx_n value doesn't match with yt. With the code below, I can round up but it goes all the way to 1. For example,
one of the cx_n values is 0.58, I want to round up 0.6, not 1.0. How can I accomplish this?
This is my MATLAB Code:
Fn = 3; %Nyquist Frequency
Fnr = 6; %Nyquist Rate
Fs = Fnr*5; %Sampling frequency
Ts = 1 / Fs; %Sampling period
T = 1 / 3;
N = T / Ts; %Number of samples per period
start = 0;
stop =N-1;
c_increment = 1;
c_n = start:c_increment:stop;
c_nTs = c_n*Ts;
cx_n = sin(2*pi*3*c_nTs);
for m_d = 1:length(cx_n)
for quantisation = 1:length(yt)
if (m_d ~= quantisation )
p = round(cx_n);
stem(c_nTs, p);
end
end
end
just replace p = round(cx_n); with p = round(cx_n,1);
See MATLAB documentation: round
Y = round(X,N) rounds to N digits:
N > 0: round to N digits to the right of the decimal point.
N = 0: round to the nearest integer.
N < 0: round to N digits to the left of the decimal point.
Related
I would like to randomly produce a set of integers ranging from 1~100. After sorting the integers, the minimum interval between each integer should not be less than a 2. For example
2,4,8,10
satisfies the requirement while the following set
2,4,5,7
does not since the interval between 4 and 5 is less than 2.
Is there any way to achieve this? Thanks!
N = 10; % number of integers required
delta = 2; % minimum difference required
a = randperm(100);
idx = 1;
b = a(idx);
while(length(b) < N && idx < length(a))
idx = idx+1;
c = abs(b - a(idx));
if any(c < delta)
continue;
end
b = [b; a(idx)];
end
b
I'm trying to get volume-time graph of .wav file. First, I recorded sound (patient exhalations) via android as .wav file, but when I read this .wav file in MATLAB it has negative values. What is the meaning of negative values? Second, MATLAB experts could you please check if the code below does the same as written in my comments? Also another question. Y = fft(WindowArray);
p = abs(Y).^2;
I took the power of values returned from fft...is that correct and what is the goal of this step??
[data, fs] = wavread('newF2');
% read exhalation audio wav file (1 channel, mono)
% frequency is 44100 HZ
% windows of 0.1 s and overlap of 0.05 seconds
WINDOW_SIZE = fs*0.1; %4410 = fs*0.1
array_size = length(data); % array size of data
numOfPeaks = (array_size/(WINDOW_SIZE/2)) - 1;
step = floor(WINDOW_SIZE/2); %step size used in loop
transformed = data;
start =1;
k = 1;
t = 1;
g = 1;
o = 1;
% performing fft on each window and finding the peak of windows
while(((start+WINDOW_SIZE)-1)<=array_size)
j=1;
i =start;
while(j<=WINDOW_SIZE)
WindowArray(j) = transformed(i);
j = j+1;
i = i +1;
end
Y = fft(WindowArray);
p = abs(Y).^2; %power
[a, b] = max(abs(Y)); % find max a and its indices b
[m, i] = max(p); %the maximum of the power m and its indices i
maximum(g) = m;
index(t) = i;
power(o) = a;
indexP(g) = b;
start = start + step;
k = k+1;
t = t+1;
g = g+1;
o=o+1;
end
% low pass filter
% filtering noise: ignor frequencies that are less than 5% of maximum frequency
for u=1:length(maximum)
M = max(maximum); %highest value in the array
Accept = 0.05* M;
if(maximum(u) > Accept)
maximum = maximum(u:length(maximum));
break;
end
end
% preparing the time of the graph,
% Location of the Peak flow rates are estimated
TotalTime = (numOfPeaks * 0.1);
time1 = [0:0.1:TotalTime];
if(length(maximum) > ceil(numOfPeaks));
maximum = maximum(1:ceil(numOfPeaks));
end
time = time1(1:length(maximum));
% plotting frequency-time graph
figure(1);
plot(time, maximum);
ylabel('Frequency');
xlabel('Time (in seconds)');
% plotting volume-time graph
figure(2);
plot(time, cumsum(maximum)); % integration over time to get volume
ylabel('Volume');
xlabel('Time (in seconds)');
(I only answer the part of the question which I understood)
Per default Matlab normalizes the audio wave to - 1...1 range. Use the native option if you want the integer data.
First, in your code it should be p = abs(Y)**2, this is the proper way to square the values returned from the FFT. The reason why you take the absolute value of the FFT return values is because those number are complex numbers with a Real and Imaginary part, therefore the absolute value (or modulus) of an imaginary number is the magnitude of that number. The goal of taking the power could be for potentially obtaining an RMS value (root mean squared) of your overall amplitude values, but you could also have something else in mind. When you say volume-time I assume you want decibels, so try something like this:
def plot_signal(file_name):
sampFreq, snd = wavfile.read(file_name)
snd = snd / (2.**15) #Convert sound array to floating point values
#Floating point values range from -1 to 1
s1 = snd[:,0] #left channel
s2 = snd[:,1] #right channel
timeArray = arange(0, len(snd), 1)
timeArray = timeArray / sampFreq
timeArray = timeArray * 1000 #scale to milliseconds
timeArray2 = arange(0, len(snd), 1)
timeArray2 = timeArray2 / sampFreq
timeArray2 = timeArray2 * 1000 #scale to milliseconds
n = len(s1)
p = fft(s1) # take the fourier transform
m = len(s2)
p2 = fft(s2)
nUniquePts = ceil((n+1)/2.0)
p = p[0:nUniquePts]
p = abs(p)
mUniquePts = ceil((m+1)/2.0)
p2 = p2[0:mUniquePts]
p2 = abs(p2)
'''
Left Channel
'''
p = p / float(n) # scale by the number of points so that
# the magnitude does not depend on the length
# of the signal or on its sampling frequency
p = p**2 # square it to get the power
# multiply by two (see technical document for details)
# odd nfft excludes Nyquist point
if n % 2 > 0: # we've got odd number of points fft
p[1:len(p)] = p[1:len(p)] * 2
else:
p[1:len(p) -1] = p[1:len(p) - 1] * 2 # we've got even number of points fft
plt.plot(timeArray, 10*log10(p), color='k')
plt.xlabel('Time (ms)')
plt.ylabel('LeftChannel_Power (dB)')
plt.show()
'''
Right Channel
'''
p2 = p2 / float(m) # scale by the number of points so that
# the magnitude does not depend on the length
# of the signal or on its sampling frequency
p2 = p2**2 # square it to get the power
# multiply by two (see technical document for details)
# odd nfft excludes Nyquist point
if m % 2 > 0: # we've got odd number of points fft
p2[1:len(p2)] = p2[1:len(p2)] * 2
else:
p2[1:len(p2) -1] = p2[1:len(p2) - 1] * 2 # we've got even number of points fft
plt.plot(timeArray2, 10*log10(p2), color='k')
plt.xlabel('Time (ms)')
plt.ylabel('RightChannel_Power (dB)')
plt.show()
I hope this helps.
I'm working on the following problem:
I realize my code is a bit off, but I want to create a for loop that will determine whether or not the integer x (the input value) is at least less than or equal to the sum of a harmonic series.
Here is what I have so far:
function n =one_per_n(x)
if x > 10000
n = -1;
end
total = 0;
i = 0;
for i = 1:10000
if x >= total
n = ceil(total);
else
total = (1/i) + total;
end
end
I've added my attempt at a while loop. I realize it's wrong, but any help would be appreciated.
function n =one_per_n(x)
if x > 10000
n = -1;
end
total = 0;
i = 0;
for i = 1:10000
while total <= x
total = (1/i) + total;
end
end
n = total;
you don't need to use some loops:
function n = one_per_n(x)
lim = min(10000,exp(x));
value = cumsum(1./(1:lim));
n = find(value >= x,1);
if isempty(n)
n = -1;
end
A while loop is a better option in this case I think
function [total, n] = one_per_n(x)
% This is a good initial check, good work
if x > 10000
n = -1;
return;
end
% Initialize the variables
total = 0;
n = 0;
% While not finished
while (total < x)
% Number of terms
n = n + 1;
total = total + 1/n;
end
end
I'm trying to multiply (element wise) a vector V of length N by a randomly generated number in the range (a,b), while keeping the sum of the vector equal to a total amount, E. I want to do this in MATLAB, but I'm not sure how. Getting random numbers between a certain range I know how to do:
minrand = 0;
maxrand = 1;
randfac = (maxrand-minrand).*rand(1,N) + minrand;
But yeah, beyond that I'm pretty clueless. I guess the random numbers can't really be generated like this, because if we call the random numbers the vector R, then I want that
R_1*V1 + R_2*V2 .... + R_N*V_N = E. So I guess it's a big equation. Is there any way to solve it, while putting constraints on the max and min values of R?
You can pick pairs of two elements (in all combinations) and add and subtract an equal random number.
% Make up a random vector
N=10;
randfac = 10*rand(1,N);
%OP Answer here: Given randfac with sum E re-randomize it
E = sum(randfac);
minrand = 0;
maxrand = 2;
disp(randfac)
% v = [6.4685 2.9652 6.6567 1.6153 7.3581 0.0237 7.1025
% 3.2381 1.9176 1.3561]
disp(sum(randfac))
% E = 38.7019
r = minrand + (maxrand-minrand)*rand(N*N,1);
k = 1;
for i=1:N
for j=1:N
randfac(i) = randfac(i)-r(k);
randfac(j) = randfac(j)+r(k);
k = k + 1;
end
end
disp(randfac)
% v = [5.4905 0.7051 4.7646 1.3479 9.3722 -1.4222 7.9275
% 7.5777 1.7549 1.1836]
disp(sum(randfac))
% E = 38.7019
Just divide the vector with the sum and multiply with the target E.
randfac = (maxrand-minrand).*rand(1,N) + minrand;
randfac = E*randfac/sum(randfac);
as long as the operator is linear, the result is going to retain it's randomness. Below is some sample code:
minrand = 0;
maxrand = 1;
N = 1000; %size
v = (maxrand-minrand).*rand(1,N) + minrand;
E = 100; %Target sum
A = sum(v);
randfac = (E/A)*v;
disp(sum(randfac))
% 100.0000
First of all with random numbers in the interval of [a b] you can't guarantee that you will have the same summation (same E). For example if [a b]=[1 2] of course the E will increase.
Here is an idea, I don't know how random is this!
For even N I randomize V then divide it in two rows and multiply one of them with random numbers in [a b] but the second column will be multiplied to a vector to hold the summation fixed.
N = 10;
V = randi(100,[1 N]);
E = sum(V);
idx = randperm(N);
Vr = V(idx);
[~,ridx] = sort(idx);
Vr = reshape(Vr,[2 N/2]);
a = 1;
b = 3;
r1 = (b - a).*rand(1,N/2) + a;
r2 = (sum(Vr) - r1.*Vr(1,:))./Vr(2,:);
r = reshape([r1;r2],1,[]);
r = r(ridx);
Enew = sum(V.*r);
The example results are,
V = [12 82 25 51 81 51 31 87 6 74];
r = [2.8018 0.7363 1.9281 0.5451 1.9387 -0.4909 1.3076 0.8904 2.9236 0.8440];
with E = 500 as well as Enew.
I'm simply assigning one random number to a pair (It can be considered as half random!).
Okay, I have found a way to somewhat do this, but it is not elegant and there are probably better solutions. Starting with an initial vector e, for which sum(e) = E, I can randomize its values and end up with an e for which sum(e) is in the range [(1-threshold)E,(1+thresholdE)]. It is computationally expensive, and not pretty.
The idea is to first multiply e by random numbers in a certain range. Then, I will check what the sum is. If it is too big, I will decrease the value of the random numbers smaller than half of the range until the sum is no longer too big. If it is too small, I do the converse, and iterate until the sum is within the desired range.
e = somepredefinedvector
minrand = 0;
maxrand = 2;
randfac = (maxrand-minrand).*rand(1,N) + minrand;
e = randfac.*e;
threshold = 0.001;
while sum(e) < (1-threshold)*E || sum(e) > (1+threshold)*E
if sum(e) > (1+threshold)*E
for j = 1:N
if randfac(j) > (maxrand-minrand)/2
e(j) = e(j)/randfac(j);
randfac(j) = ((maxrand-minrand)/2-minrand).*rand(1,1) + minrand;
e(j) = randfac(j)*e(j);
end
if sum(e) > (1-threshold)*E && sum(e) < (1+threshold)*E
break
end
end
elseif sum(e) < (1-threshold)*E
for j = 1:N
if randfac(j) < (maxrand-minrand)/2
e(j) = e(j)/randfac(j);
randfac(j) = (maxrand-(maxrand-minrand)/2).*rand(1,1) + (maxrand-minrand)/2;
e(j) = randfac(j)*e(j);
end
if sum(e) > (1-threshold)*E && sum(e) < (1+threshold)*E
break
end
end
end
end
I have two matrices of big sizes, which are something similar to the following matrices.
m; with size 1000 by 10
n; with size 1 by 10.
I would like to subtract each element of n from all elements of m to get ten different matrices, each has size of 1000 by 10.
I started as follows
clc;clear;
nrow = 10000;
ncol = 10;
t = length(n)
for i = 1:nrow;
for j = 1:ncol;
for t = 1:length(n);
m1(i,j) = m(i,j)-n(1);
m2(i,j) = m(i,j)-n(2);
m3(i,j) = m(i,j)-n(3);
m4(i,j) = m(i,j)-n(4);
m5(i,j) = m(i,j)-n(5);
m6(i,j) = m(i,j)-n(6);
m7(i,j) = m(i,j)-n(7);
m8(i,j) = m(i,j)-n(8);
m9(i,j) = m(i,j)-n(9);
m10(i,j) = m(i,j)-n(10);
end
end
end
can any one help me how can I do it without writing the ten equations inside the loop? Or can suggest me any convenient way especially when the two matrices has many columns.
Why can't you just do this:
m01 = m - n(1);
...
m10 = m - n(10);
What do you need the loop for?
Even better:
N = length(n);
m2 = cell(N, 1);
for k = 1:N
m2{k} = m - n(k);
end
Here we go loopless:
nrow = 10000;
ncol = 10;
%example data
m = ones(nrow,ncol);
n = 1:ncol;
M = repmat(m,1,1,ncol);
N = permute( repmat(n,nrow,1,ncol) , [1 3 2] );
result = bsxfun(#minus, M, N );
%or just
result = M-N;
Elapsed time is 0.018499 seconds.
or as recommended by Luis Mendo:
M = repmat(m,1,1,ncol);
result = bsxfun(#minus, m, permute(n, [1 3 2]) );
Elapsed time is 0.000094 seconds.
please make sure that your input vectors have the same orientation like in my example, otherwise you could get in trouble. You should be able to obtain that by transposements or you have to modify this line:
permute( repmat(n,nrow,1,ncol) , [1 3 2] )
according to your needs.
You mentioned in a comment that you want to count the negative elements in each of the obtained columns:
A = result; %backup results
A(A > 0) = 0; %set non-negative elements to zero
D = sum( logical(A),3 );
which will return the desired 10000x10 matrix with quantities of negative elements. (Please verify it, I may got a little confused with the dimensions ;))
Create the three dimensional result matrix. Store your results, for example, in third dimension.
clc;clear;
nrow = 10000;
ncol = 10;
N = length(n);
resultMatrix = zeros(nrow, ncol, N);
neg = zeros(ncol, N); % amount of negative values
for j = 1:ncol
for i = 1:nrow
for t = 1:N
resultMatrix(i,j,t) = m(i,j) - n(t);
end
end
for t = 1:N
neg(j,t) = length( find(resultMatrix(:,j,t) < 0) );
end
end