Harmonic Product Spectrum using MATLAB - matlab

Im tying to find the fundamental frequency of a note using harmonic product spectrum. This is the part that implements the HPS algorithm
seg_fft = seg_fft(1 : size(seg_fft,1)/2 ); % FFT data
seg_fft = abs(seg_fft);
seg_fft2 = ones(size(seg_fft));
seg_fft3 = ones(size(seg_fft));
seg_fft4 = ones(size(seg_fft));
seg_fft5 = ones(size(seg_fft));
for i = 1:floor((length(seg_fft)-1)/2)
seg_fft2(i,1) = (seg_fft(2*i,1) + seg_fft((2*i)+1,1))/2;
end
for i = 1:floor((length(seg_fft)-2)/3)
seg_fft3(i,1) = (seg_fft(3*i,1) + seg_fft((3*i)+1,1) + seg_fft((3*i)+2,1))/3;
end
for i = 1:floor((length(seg_fft)-3)/4)
seg_fft4(i,1) = (seg_fft(4*i,1) + seg_fft((4*i)+1,1) + seg_fft((4*i)+2,1) + seg_fft((4*i)+3,1))/4;
end
for i = 1:floor((length(seg_fft)-4)/5)
seg_fft5(i,1) = (seg_fft(5*i,1) + seg_fft((5*i)+1,1) + seg_fft((5*i)+2,1) + seg_fft((5*i)+3,1) + seg_fft((5*i)+4,1))/5;
end
f_ym = (seg_fft) .* (seg_fft2) .* (seg_fft3) .* (seg_fft4) .*(seg_fft5);
Now when i play F4, the 2nd harmonic(698 -F5) has a higher amplitude. So HPS is supposed to help me detect the fundamental which is F4 and NOT F5.
When i do the HPS these are the graphs I get:
The figures above show the plots of seg_fft2, seg_fft3, seg_fft4 and seg_fft5 respectively.
But what I dont understand is how come the frequency points obtained in these graphs are not factors of the original spectrum?? Isn't that how HPS is supposed to work??
This is the plot I obtained when I took the product of all 5.
the peak is at 698Hz.. But shouldn't it be at 349Hz instead??
But after the whole code is run, I do get the fundamental as F4.. Its all very confusing.... Can someone tell me why my graphs are different from what is expected yet I get the correct fundamental please????
This is the rest of the code
%HPS, PartIII: find max
f_y1 = max(f_ym)
for c = 1 : length(f_ym)
if(f_ym(c,1) == f_y1)
index = c;
end
end
% Convert that to a frequency
f_y(h) = (index / NFFT) * FS;
h=h+1;
%end
V = abs(f_y);
Please do help...... Thanx in advance....

Related

How to isolate a frequency range in MATLAB using signals concepts?

I am trying to use concepts learned in signals analysis to isolate a specific frequency from a sound file. I have a short WAV file that consists of a person talking but also has other noises with unknown frequencies both above and below the desired signal. I have an upper and lower bound for the frequency range that should contain the part of the sound I want.
I think I should be able to do this without using the signals analysis toolbox or the butter filter.
so far I have this code which plots the power spectrum for the signal:
[y, Fs] = audioread('filename.wav','double');
t = 1:1:length(y);
y = transpose(y);
a = ifft(y);
a_k = abs([a((length(y)/2)+1:-1:2),a(1:1:(length(y)/2)+1)]);
bar((-length(y)/2)+1:1:(length(y)/2),a_k);
The power spectrum looks like this:
I think I should be able to use what I have to filter our anything above or below my known range, but I am not sure how to start doing that.
To apply ideal band pass filter you can use the code below. However, please note that the ideal filter may not produce the most optimal results if your signal is not periodic (see the wiki article here).
%% Initialisation
Fs = 44100;
t0 = 0;
t1 = 1;
t = t0 : 1/Fs : t1;
f1 = 10;
f2 = 40;
y = 10*cos(2*pi*f1*t) + 20*sin(2*pi*f2*t);
%% Cosine series
true_fft = fft(y);
nfft = length(y);
% The number of unique points
if mod(nfft, 2) == 0
num_pts = round(nfft/2) + 1;
else
num_pts = ceil(nfft/2);
end
% The vector that contains only unique points
fftT = true_fft(1 : num_pts);
% The vector that contains the unique frequencies
u_f = (0 : num_pts-1)*Fs/nfft;
%% Filtered signal
% Definition of the frequency band
f_low = 5;
f_high = 15;
[~, idx_low] = min(abs(u_f - f_low));
[~, idx_high] = min(abs(u_f - f_high));
filtFFTT = fftT;
filtFFTT([1: idx_low idx_high : end]) = 0;
if mod(nfft, 2) == 0
filtFFTT = [filtFFTT conj(filtFFTT((end - 1) : -1 : 2))];
else
filtFFTT = [filtFFTT conj(filtFFTT(end : -1 : 2))];
end
%% Data visualisation
figure;
plot(t, ifft(filtFFTT));

Forecast future values from FFT

In the attached code I create an arbitrarily complex signal generator (3 sine waves in this case) and generate 256 + 50 values using it. I then create an FFT using the first 256 values, plot them and then do an inverse FFT and verify that it produces a very close representation of the original signal. All good so far.
What I'd like to do now is, using the FFT results, attempt to generate the additional 50 values that were not part of the FFT data set. Is there a straight-forward in MatLab?
Without being exactly sure how I assume I can create a signal generator using the center frequency of each bin and the FFT result and generate the signal that way, but that does seem like a lot of work so before I went down that path I figured I'd see if there was an easy way that I just haven't found.
I have MatLab & the Signal Processing and DSP packages to use at this time.
Thanks!
FFTsize = 256;
futureSize = 50;
t = 1:FFTsize+futureSize;
F1_bars = 10;
RadPerBar1 = (2*pi)/F1_bars;
L1 = 1;
Offset1 = 0;
F2_bars = 8;
RadPerBar2 = (2*pi)/F2_bars;
L2 = 1;
Offset2 = 0;
F3_bars = 50;
RadPerBar3 = (2*pi)/F3_bars;
L3 = 1;
Offset3 = 0;
Sig = (L1*sin(RadPerBar1*t + Offset1) +...
L2*sin(RadPerBar2*t + Offset2) +...
L3*sin(RadPerBar3*t + Offset3));
DataSet = Sig(1:FFTsize);
FFT = fft(DataSet)/FFTsize;
%Suggested by Mad Physicist
paddedFFT = [FFT(1:ceil(FFTsize/2)) zeros(1, futureSize) FFT(ceil(FFTsize/2)+1 : end)];
IFFT = ifft(FFT)*FFTsize;
%Suggested by Mad Physicist
IFFT2 = ifft(paddedFFT)*(FFTsize + futureSize);
figure(111);
hold off;
plot(abs(FFT));
hold on;
plot(abs(paddedFFT),'--r');
legend('FFT','Padded FFT','Position','best');
hold off;
figure(110)
hold off;
plot(Sig);
hold on;
plot(IFFT,'--r');
plot(t, IFFT2,'g');
legend('Input Signal','IFFT','Padded IFFT','Position','best');
hold off;
Pad the FFT with 50 zeros before you invert it:
futureSize = 50;
paddedFFT = [FFT(1:ceil(FFTsize/2)) zeros(1, futureSize) FFT(ceil(FFTsize/2)+1 : end)];
IFFT = ifft(paddedFFT)*(FFTsize + futureSize);

Simple Phase Shift for Removing Instrument Response

So I have a simple program where I want to shift a simple sine function pi/2. Now I knwo this would be extremely easy by just inserting a bias (i.e. A*sin(2*pi*frequency + bias). But this program is a simple way to test a theory. I need to shift complicated magnetic data, but the shift is frequency dependent. So to figure out how to do that I just want to shift this sin wave by a set shift, but I want to do it in the frequency domain. While the code below doesn't show any errors, it does not shift the data properly and effects magnitude. Code is below. Thank you!
clear all
time = 1:0.01:2*pi; %Create time vector
mag = sin(2*pi*time);
Y = fft(mag); %transform
Pnewr = pi/2;
%t = angle(mag);
t = imag(Y);
%t_fin = t-Pnewr; %Subtract the pahse delay from the original phase vector
R=real(Y);
I=t;
k = I./R
Phi = tan(k);
PhiFinal = Phi-Pnewr;
PhiFinal = PhiFinal'
IFinal = R * atan(PhiFinal);
spec=complex(R,IFinal);
Finalspec = ifft(spec); %Invert the transform
Final = Finalspec;
plot(time,mag);
hold on
plot(time,Final,'r')
grid on
For one thing you are not recombining imaginary and real components properly, since
PhiFinal = PhiFinal'
IFinal = R * atan(PhiFinal);
is effectively a dot product, not an element by element product. In general it doesn't look like you are making correct use of the complex relationships. The following generates a clean phase shift:
time = 1:0.01:2*pi;
mag = sin(2*pi*time);
Y = fft(mag); %transform
Pnewr = pi/2;
R = real(Y);
I = imag(Y);
It = abs(Y);
% It = sqrt(I.^2 + R.^2);
Phi= angle(Y); % <-- using matlab function, equivalent to `Phi = atan2(I, R);`
k = I./R;
Phi0 = atan(k);
figure, subplot(121), plot(Phi0,Phi,'.'), xlabel('Phi from tan'), ylabel('Phi from ''angle'''), grid on, axis('tight')
PhiFinal = Phi-Pnewr; % <-- phase shift
IFinal = It .* sin(PhiFinal);
RFinal = It .* cos(PhiFinal);
spec= RFinal + 1i*IFinal;
Final = ifft(spec); %Invert the transform
subplot(122)
plot(time,mag);
hold on
plot(time,real(Final),'r')
plot(time,imag(Final),'r:')
grid on
axis('tight')
legend('Initial','Final'),xlabel('t'), ylabel('I')
mag*mag' % <-- check that total power is conserved
Final*Final'
These figures show the phase as computed with tan vs matlab's angle (which uses atan2), and the results of the phase shift (right panel):

does white noise without mean zero do some changes?

again my question is related to white noise ,but with different meaning.let us compare following two code.first
function [ x ] = generate(N,m,A3)
f1 = 100;
f2 = 200;
T = 1./f1;
t = (0:(N*T/m):(N*T))'; %'
wn = rand(length(t),1).*2 - 1;
x = 20.*sin(2.*pi.*f1.*t) + 30.*cos(2.*pi.*f2.*t) + A3.*wn;
%[pks,locs] = findpeaks(x);
plot(x)
end
using generate(3,500,10)
graph of this code is following
but let us change our code so that it makes zero mean with white noise
function [ x ] = generate1(N,m,A3)
f1 = 100;
f2 = 200;
T = 1./f1;
t = (0:(N*T/m):(N*T))'; %'
wn = rand(length(t),1).*2 - 1;
mn=wn-mean(wn);
x = 20.*sin(2.*pi.*f1.*t) + 30.*cos(2.*pi.*f2.*t) + A3.*mn;
%[pks,locs] = findpeaks(x);
plot(x)
end
and graph is following
if we compare these two picture,we could say that it is almost same,just some changes,so does matter if we make zero mean or not?for real analysis,like for finding
peaks and so on.thanks very much
UPDATED:
there is updated code
function [ x ] = generate1(N,m,A3)
f1 = 100;
f2 = 200;
T = 1./f1;
t = (0:(N*T/m):(N*T))'; %'
wn = randn(length(t),1); %zero mean variance 1
x = 20.*sin(2.*pi.*f1.*t) + 30.*cos(2.*pi.*f2.*t) + A3.*wn;
%[pks,locs] = findpeaks(x);
plot(x)
end
and it's picture
Your initial noise is uniformly distributed between -1 & +1
Your second noise is also uniformly disributed between -1 & +1, because mean is already zero, subtracting it is meaningless
in order to obtain white noise you can use randn() function:
wn = randn(length(t),1); %zero mean variance 1
You may not observe any much difference again if your noise coefficient A3 has a much lower value compared to 20 & 30 which are the coefficients of your signal.
In order to find peaks, adding noise may not serve any purpose because noise tends to decrease the information content of signals
What is the value of mean(wm)? If it is close to zero, then no, it does not matter.
Technically, white noise has zero mean by definition.

no oscillation after put in pid controller

I have a problem regarding putting a PID controller in my simulink file.
In my simulink file, i used pid controller to control my process. I used s-function as my process block diagram.
According Ziegler-Nichols method, for the first step we set k equal to the smallest value (0.5) so I put 0.5 in my proportional value . but there is no different between the result with controller and without controller.Even i increase or decrease proportional value.
Why this problem occur? hope someone can help me.Thank you.
my block diagram is look like below picture.refer to this picture
http://s1009.photobucket.com/albums/af218/syarinazulkifeli/?action=view&current=Untitled-1.png
Here is my s-function file:
function [sys,x0,str,ts]= reactor_sfcn(t,x,u,flag)
switch flag
case 0
[sys,x0,str,ts]=mdlInitializeSizes;
case 1,
sys = mdlDerivatives(t,x,u);
case 3,
sys = mdlOutputs(t,x,u);
case 9
sys =[];
end
function [sys,x0,str,ts] = mdlInitializeSizes()
s = simsizes;
s.NumContStates = 11;
s.NumDiscStates = 0;
s.NumOutputs = 11;
s.NumInputs = 1;
s.DirFeedthrough = 0;
s.NumSampleTimes = 1;
sys = simsizes(s) ;
x0 = [0.0258,0,0,0,0,0,0,0,8.83,303.15,303.15];
str=[] ;
ts = [0 0];
function sys = mdlDerivatives (t,x,u)
Tjo = u;
sys = reactor(t,x,Tjo);
function sys = mdlOutputs(t,x,u)
% sys(1)=x(1);
% sys(2)=x(2);
% sys(3)=x(3);
% sys(4)=x(4);
% sys(5)=x(5);
% sys(6)=x(6);
% sys(7)=x(7);
% sys(8)=x(8);
% sys(9)=x(9);
% sys(10)=x(10);
% sys(11)=x(11);
sys = x;
Link of s-function file
function DXDT = reactor(t,x,Tjo)
% -------------------------------------------- %
% Parameters definition
% -------------------------------------------- %
I = x(1); X = x(2); P0 = x(3);
P1 = x(4); P2 = x(5); Q0 = x(6);
Q1 = x(7); Q2 = x(8); M = x(9);
Tjo = x(10); T = x(11);
% ---------------------------------------
% Constants
% =======================================
%constant
M0 = 8.83;
I0 = 0.0258;
Qh = 60.44;
MMWm = 100.3;
U0 = 55.1;
% Densities
dp = 1200;
dm = 968-1.225*(T-273.15);
Rhoc = 998;
% volume expansion factor
Fev = (dm - dp)./dp ;
% volume fraction
Fvm = (1 - X)./(1 + Fev*X);
Fvp = X*(1-Fev)./(1+Fev*X);
% Total reactant mixture density
Rho = dm*Fvm + dp*Fvp;
% Reactor and jacket volume
Vc = 2;
V = 2;
% Reactor dimension
At =3.1416*0.15*0.113;
% coolant flow rate
Mc = 0.41/18;
%
Cpc = 77.22;
Cp = 199.13;
% Average coolant temperature
Tji = 303.15;
Tj =(Tji+Tjo)/2;
% Overall heat transfer coeff
alpha = 0.4;
U = U0-alpha*X;
delHp = 57800;
% ---------------------------------------
% Rates of reaction
% =======================================
% Fujita-Doolittle equation
Tgp = 114 +273.25 ;
A = 0.168-8.21e-6*(T-Tgp)^2;
B = 0.03;
g = exp(2.303*Fvm/(A + B*Fvm));
% Dissociation rate
F = 0.58;
Kd = (6.32e16*exp(-15.43e3/T));
% Propagation rate
Tep = 5.4814e-16*exp(13982/T);
Kp0 = 2.952e7*exp(-4353/(1.987*T));
Kp = (Kp0*g)./(g + (Tep*P0.*Kp0));
% Termination rate
Tet = (1.1353e-22*exp(17420/T))./I0;
Kt0 = 5.88e9*exp(-701/(1.987*T));
Kt = (Kt0*g)./(g + (Tet*P0.*Kt0));
Ktc = 0;
Ktd = Kt ;
% -------------------------------------------- %
% ODE's
% -------------------------------------------- %
dIdt = -Kd*I - ((Fev*I.*P0.*(1 - X)*Kp)./(1 + Fev*X));
dXdt = Kp*(1 - X).*P0;
dP0dt = (-Fev*P0.*P0.*(1 - X)./(1 + Fev*X)).*Kp + 2*F*Kd*I - Kt*P0.*P0;
dP1dt = (-Fev*P0.*P1.*(1 - X)./(1 + Fev*X)).*Kp + 2*F*Kd*I - Kt*P0.*P1 + (Kp*M0*(1 - X)./(1 + Fev*X)).*P0;
dP2dt = (-Fev*P0.*P2.*(1 - X)./(1 + Fev*X)).*Kp + 2*F*Kd*I - Kt*P0.*P2 + (Kp*M0*(1 - X)./(1 + Fev*X)).*(2*P1 + P0);
dQ0dt = (-Fev*P0.*Q0.*(1 - X)./(1 + Fev*X)).*Kp + Ktd*P0.*P0 + 0.5*Ktc*P0.*P0;
dQ1dt = (-Fev*P0.*Q1.*(1 - X)./(1 + Fev*X)).*Kp + Ktd*P0.*P1 + Ktc*P0.*P1;
dQ2dt = (-Fev*P0.*Q2.*(1 - X)./(1 + Fev*X)).*Kp + Ktd*P0.*P2 + Ktc*(P1.*P0 + P1.^2);
dMdt = (-Kp*P0*M0*(1 - X)./(1 + Fev*X)).*((Fev*(1 - X)./(1 + Fev*X)) + 1);
Rm = (-delHp)*dMdt;
dTjodt = (Mc*Cpc*(Tji-Tjo)+ U*At*(T-Tj))/(Vc*Rhoc*Cpc/18);
dTdt = (Qh+(Rm*V*MMWm)-(U*At*(T-Tj)))/(V*Rho*Cp);
DXDT =[dIdt;dXdt;dP0dt;dP1dt;dP2dt;dQ0dt;dQ1dt;dQ2dt;dMdt;dTjodt;dTdt];
First I woult check if the s-function for the process is working as expected. Disconnect the PID controller and connect a step, ramp or a sin block. This could give you a hint if the block for the process is OK and how large the static coefficient is.
A second hint: the Ziegler-Nichols method says one should increase the Kp until the system gets marginaly stable. Have you tested only one value for the proportional gain? Depending on the plant 0.5 can be really small value and way under the levels you need to control the system.
You change the Kp term but there is no change...did you give the system a step command? Is the actual and desired signal error being fed back to the PID controller? If these are satisfied and the system is still insensitive to Kp you may need to go through your model block by block to find the issue. Also, why are you modelling your plant with an S function? Implementing these can be tricky. I would much rather see the plant model in diagram form, or at least in embedded m.
For the step input I would recommend this link or google it. You need to set the Kp fairly high and then give it a step command input to destabilize the system and then vary Kp until it's stable and measure the period of oscillation.
I put together a toy model for you to test, I am inclined as well to beleive your s-function is at fault here. If you want to post/send the sfunction, I'd be glad to look at it. However, if you want to learn Ziegler-Nichols, start with a very simple model and follow the steps in the Ziegler-Nichols process. Here's the output for some of my data with a Kp = 200 and a plant of 1/(s+1):
So you can see the oscillation above. Kp = 200 is way too high, you'd have to reduce it quite a bit for Ziegler-Nichols, but I just wanted to give you an example.
EDIT I downloaded your readtor_sfcn and reactor function into two files named
reactor_sfcn.m and reactor.m Right away, I can tell why you never see any
change in the input. In the reactor_sfcn mdlDerivatives, you pass the input
to the system u as the third parameter to the reactor function. In the
reactor function I can see that the third parameter, Tjo is never read,
but overwritten with x(10). So, if Tjo is supposed to be the input parameter
it shouldn't also be a state. That will be up to you to solve that problem,
it is specific to your implementation of the plant. I've got a test model
I've used to look at your files, I'll try to put it somewhere you can get
access to it soon, but it likely won't be as useful as you analyzing what
the plant is supposed to be doing. Hope this helps!
Thanks!