Bulk chirp creation in Matlab - matlab

This is more some assistance in helping to automate chirp creation using the signal processing tools.
So basically using the chirp tool I'm trying to see if I can bulk generate 990 chirps (in a frequency range of 5-500Hz both upsweep and downsweep) so I can then do some statistics on them to define a best fit model through correlation without physically having to type out and generate all these chirps.
Example:
ch_6_60_10_lin=chirp(0:0.004:10,6,10,60,'linear',90);
To generate a chirp between 6Hz and 60Hz over a 10s interval.
I want to be able to generate 495 variables in these formats
ch_5_[5:500]_10_lin=chirp(0:0.004:10,5,10,[5:500],'linear',90) % where [5:500] are 495 steps
ch_[5:500]_500_10_lin=chirp(0:0.004:10,[5:500],10,500,'linear',90)
Any pointers in the right direction would be greatly appreciated!

Are you sure you want all of those as independent variables? It would probably be easier to manage all of this as a matrix.
tVec = 0:0.004:10; % Vector of time samples
f1Vec = 5:500; % Vector of ending frequencies for the first set of chirps
f2Vec = 5:000; % Vector of starting frequencies for the second set of chirps
nChirps1 = length(f1Vec);
nChirps2 = length(f2Vec);
nTimeSamples = length(tVec);
chirpMat1 = zeros(nChirps1, nTimeSamples);
chirpMat2 = zeros(nChirps2, nTimeSamples);
for iChirp = 1:nChirps1
chirpMat1(iChirp, :) = chirp(tVec, 5, 10, f1Vec(iChirp), 'linear', 90);
end
for iChirp = 1:nChirps2
chirpMat2(iChirp, :) = chirp(tVec, f0Vec(iChirp), 10, 500, 'linear', 90);
end

Related

simulate and estimate ARMA model

I'm trying to simulate an ARMA model and later simulate the AR and MA polynomial coefficients from the simulated time series.
I found the following ARIMA function in MatLab that I hoped help me achieve my goal.
Looking at the provided examples, I thought this would work:
AR_coef = {0.5, -0.1};
MA_coef = {0.8, 0.5, 0.3};
% simulate time series
Mdl_in = arima('AR', AR_coef, ...
'MA', MA_coef, ...
'Constant', 0, ...
'Variance', 1);
y = simulate(Mdl_in,1,'NumPaths',10000);
% estimate coefficients
Mdl_out = arima(numel(AR_coef), 0, numel(MA_coef));
T = numel(y);
idxpre = 1:Mdl_out.P;
idxest = (Mdl_out.P + 1):T;
EstMdl = estimate(Mdl_out,y(idxest)','Y0',y(idxpre)');
My hope was that EstMdl returns the AR_coef and MA_coef but it does not.
Based on the random number generation, the estimated model parameter varies a lot.
Can someone help me generate an example where I simulate an ARMA model and later estimate its coefficients?
I'm also fine with using Python if it is easier.

Finding fundamental frequency .wav file Matlab

I have to extract the fundamental frequency from a .wav file of 1 second long.
I have looked over several options like finding the peaks or doing a complex cepstrum but no luck so far. I have read over the last couple of weeks a lot about it but still i cannot find a viable and optimal way of doing it. I am new to Matlab and Signal Processing.
filedir = dir('*.wav');
[y, Fs] = audioread(filedir.name);
x = y(y ~= 0) % removing the zeroes from the array
psdest = psd(spectrum.periodogram,x,'Fs',Fs,'NFFT',length(x));
[~,I] = max(psdest.Data);
fprintf('Maximum occurs at %d Hz.\n',psdest.Frequencies(I));
The output is for example: Maximum occurs at 5.758645e+02 Hz
I will probably need to actually transform that number into Hz.
For the complex cepstrum:
load mtlb
dt = 1/Fs;
I0 = round(0.1/dt);
Iend = round(1/dt);
x = mtlb(I0:Iend);
c = cceps(x);
t = 0:dt:length(x)*dt-dt;
trng = t(t>=2e-3 & t<=10e-3);
crng = c(t>=2e-3 & t<=10e-3);
[~,I] = max(crng);
fprintf('Complex cepstrum F0 estimate is %3.2f Hz.\n',1/trng(I))
clearvars
The output values is the same for all the files I load so clearly something is wrong.
I have been struggling for a while and I really need to figure this out. To extract that fundamental frequency. I use Matlab 2016b.
Thanks a lot!

Calculate 3dB bandwidth at a peak from magnitude-frequency plot

I need to calculate the 3dB bandwidth from data containing Power in dB vs Frequency in Hz. For instance:
X =
2.9640 -5.0568
2.9705 -4.5819
2.9770 -4.1277
2.9835 -3.7016
2.9900 -3.3095
2.9965 -2.9560
3.0030 -2.6446
3.0095 -2.3776
3.0160 -2.1569
3.0225 -1.9839
3.0290 -1.8596
3.0355 -1.7847
3.0420 -1.7596
3.0485 -1.7849
3.0550 -1.8609
3.0615 -1.9877
3.0680 -2.1655
3.0745 -2.3944
3.0810 -2.6741
3.0875 -3.0044
3.0940 -3.3843
3.1005 -3.8126
3.1070 -4.2872
3.1135 -4.8051
3.1200 -5.3616
3.1265 -5.9505
I get the peak I am interested in with findpeaks builtin function:
[pks, locs, w, p] = findpeaks(X.data(:,2), 'MinPeakProminence',3);
fstpeak = locs(1);
frequency = X(fstpeak,1);
peak_magnitude = X(fstpeak,2);
I can obviously make a for loop and look forward and backward from fstpeak until I get a value of magnitude below peak_magnitude - 3, and then interpolate if more precision is required.
It seems a pretty common operation, but I have tried to find a builtin matlab function with no success. Is there a builtin function I can use, or a faster approach to the custom for loop?
I think your problem with doing this is going to be that your data is not monotonically increasing. Having said that, it does follow a nice curve - it rises to a maximum and then starts to decrease, and there is no noise. As such, you can split the curve in two shorter curves that are monotonically increasing/decreasing and use `interp1' to find the -3dB point.
frequency = X(:,1);
magnitude = (X:,2);
magnitude = magnitude - max(magnitude); % Normalise to maximum
indmax = find(magnitude == max(magnitude));
f1 = interp1(magnitude(1:indmax), frequency(1:indmax), -3);
f2 = interp1( magnitude(indmax:end), frequency(indmax:end), -3);
BW = f2 - f1;
This approach will fall down if you apply it to data that does not rise and then fall, or if you apply it to noisy data.

Reverse-calculating original data from a known moving average

I'm trying to estimate the (unknown) original datapoints that went into calculating a (known) moving average. However, I do know some of the original datapoints, and I'm not sure how to use that information.
I am using the method given in the answers here: https://stats.stackexchange.com/questions/67907/extract-data-points-from-moving-average, but in MATLAB (my code below). This method works quite well for large numbers of data points (>1000), but less well with fewer data points, as you'd expect.
window = 3;
datapoints = 150;
data = 3*rand(1,datapoints)+50;
moving_averages = [];
for i = window:size(data,2)
moving_averages(i) = mean(data(i+1-window:i));
end
length = size(moving_averages,2)+(window-1);
a = (tril(ones(length,length),window-1) - tril(ones(length,length),-1))/window;
a = a(1:length-(window-1),:);
ai = pinv(a);
daily = mtimes(ai,moving_averages');
x = 1:size(data,2);
figure(1)
hold on
plot(x,data,'Color','b');
plot(x(window:end),moving_averages(window:end),'Linewidth',2,'Color','r');
plot(x,daily(window:end),'Color','g');
hold off
axis([0 size(x,2) min(daily(window:end))-1 max(daily(window:end))+1])
legend('original data','moving average','back-calculated')
Now, say I know a smattering of the original data points. I'm having trouble figuring how might I use that information to more accurately calculate the rest. Thank you for any assistance.
You should be able to calculate the original data exactly if you at any time can exactly determine one window's worth of data, i.e. in this case n-1 samples in a window of length n. (In your case) if you know A,B and (A+B+C)/3, you can solve now and know C. Now when you have (B+C+D)/3 (your moving average) you can exactly solve for D. Rinse and repeat. This logic works going backwards too.
Here is an example with the same idea:
% the actual vector of values
a = cumsum(rand(150,1) - 0.5);
% compute moving average
win = 3; % sliding window length
idx = hankel(1:win, win:numel(a));
m = mean(a(idx));
% coefficient matrix: m(i) = sum(a(i:i+win-1))/win
A = repmat([ones(1,win) zeros(1,numel(a)-win)], numel(a)-win+1, 1);
for i=2:size(A,1)
A(i,:) = circshift(A(i-1,:), [0 1]);
end
A = A / win;
% solve linear system
%x = A \ m(:);
x = pinv(A) * m(:);
% plot and compare
subplot(211), plot(1:numel(a),a, 1:numel(m),m)
legend({'original','moving average'})
title(sprintf('length = %d, window = %d',numel(a),win))
subplot(212), plot(1:numel(a),a, 1:numel(a),x)
legend({'original','reconstructed'})
title(sprintf('error = %f',norm(x(:)-a(:))))
You can see the reconstruction error is very small, even using the data sizes in your example (150 samples with a 3-samples moving average).

MATLAB code for calculating MFCC

I have a question if that's ok. I was recently looking for algorithm to calculate MFCCs. I found a good tutorial rather than code so I tried to code it by myself. I still feel like I am missing one thing. In the code below I took FFT of a signal, calculated normalized power, filter a signal using triangular shapes and eventually sum energies corresponding to each bank to obtain MFCCs.
function output = mfcc(x,M,fbegin,fs)
MF = #(f) 2595.*log10(1 + f./700);
invMF = #(m) 700.*(10.^(m/2595)-1);
M = M+2; % number of triangular filers
mm = linspace(MF(fbegin),MF(fs/2),M); % equal space in mel-frequency
ff = invMF(mm); % convert mel-frequencies into frequency
X = fft(x);
N = length(X); % length of a short time window
N2 = max([floor(N+1)/2 floor(N/2)+1]); %
P = abs(X(1:N2,:)).^2./N; % NoFr no. of periodograms
mfccShapes = triangularFilterShape(ff,N,fs); %
output = log(mfccShapes'*P);
end
function [out,k] = triangularFilterShape(f,N,fs)
N2 = max([floor(N+1)/2 floor(N/2)+1]);
M = length(f);
k = linspace(0,fs/2,N2);
out = zeros(N2,M-2);
for m=2:M-1
I = k >= f(m-1) & k <= f(m);
J = k >= f(m) & k <= f(m+1);
out(I,m-1) = (k(I) - f(m-1))./(f(m) - f(m-1));
out(J,m-1) = (f(m+1) - k(J))./(f(m+1) - f(m));
end
end
Could someone please confirm that this is all right or direct me if I made mistake> I tested it on a simple pure tone and it gives me, in my opinion, reasonable answers.
Any help greatly appreciated :)
PS. I am working on how to apply vectorized Cosinus Transform. It looks like I would need a matrix of MxM of transform coefficients but I did not find any source that would explain how to do it.
You can test it yourself by comparing your results against other implementations like this one here
you will find a fully configurable matlab toolbox incl. MFCCs and even a function to reverse MFCC back to a time signal, which is quite handy for testing purposes:
melfcc.m - main function for calculating PLP and MFCCs from sound waveforms, supports many options.
invmelfcc.m - main function for inverting back from cepstral coefficients to spectrograms and (noise-excited) waveforms, options exactly match melfcc (to invert that processing).
the page itself has a lot of information on the usage of the package.