Data, which isn't missing, appears to be missing in surf plot

Can anyone explain the gaps (white bars) which arise in my surf plot? The degree to which they appear changes depending on whether I plot the spectrogram as a full figure or a subplot... I would like to remedy this so there are no white bars in the subplot of the spectrogram.
subplot(3,1,3)
surf(t,f,A','FaceColor','interp',...
'EdgeColor','none','FaceLighting','phong');
set(gca,'tickdir','out','layer','top','fontname',... %change size of axes
'arial','fontsize',8);
ylim([50 2000]);
axis tight
view(0,90);
grid off
set(gca,'YScale','log'); %set y-axis scale to logarithmic
datetick('x','keepticks'); %change x axis to readable time
ylabel('Frequency ( Hz )','fontsize',14);

13 Comments

set(gca,'YScale','log'); %set y-axis scale to logarithmic
I predict that you have negative A values.
No :( I have just searched for negative values using
[row col]=find(A<0)
and it produces two empty arrays.
It actually looks worse before I convert from lin to log.
Here I include a different dataset as an example, with linear on top and log below:
Please attach a .mat with t, f, A arrays for us to test with.
hello Louise
does this post has a relatioship with tthis one ?
sems there that in the other post you display the log of P which is positive real valued array, so there should not be any need to do such test : [row col]=find(A<0)
This code (other post ) does not generate any blanks BTW... :
%% read multiple files
fileDir = pwd; % currrent directory
fileNames = dir(fullfile(fileDir,'*.wav')); % get list of files in directory
fileNames_sorted = natsortfiles({fileNames.name}); % sort file names into order (https://fr.mathworks.com/matlabcentral/fileexchange/47434-natural-order-filename-sort)
nFiles = numel(fileNames_sorted);
% my own paramters value here
cal = 1;
nfft = 1024;
window = hanning(nfft);
overlap = 512;
Tstart = zeros(1,nFiles);
for iFile = 1:nFiles
fullfname = fullfile(fileDir, fileNames_sorted{iFile});
t0 = Tstart(iFile);
% [xbit,fs]=audioread(fullfname, [nlo nup]); %read in wav
[xbit,fs]=audioread(fullfname); %read in wav
xbit=detrend(xbit); %remove DC offset
calxbit=xbit*cal; %apply calibration
%Perform FFT and plot:
[S,F,T,P] = spectrogram(calxbit,window,overlap,nfft,fs,'yaxis');
sph(iFile) = subplot(nFiles,1,iFile);
h = pcolor(T,F,10*log10(P)); % Here you might want to add the start-time, t0, to T
% with proper conversion of time-format...
set(h,'EdgeColor','none');
xlabel('Time (s)');
ylabel('Frequency (Hz)');
end
test result :
Hi @Walter Roberson, thanks for your help. I have tried this again today with the same and different datasets and for some reason this issue isn't occurring today... I guess that maybe means it was an issue with my graphics card or something?
Hi @Mathieu NOE, yes, in some way. The post you reference is aimed at addressing how to plot multiple spectrograms on a single plot, using raw .wav data. The code you include does not answer the question on the post you reference as your code plots multiple subplots in a single figure. My aim is to plot multiple spectrograms on a single plot which are clearly marked by x-ticks using the start time of the .wav file plotted.
If you are able, we should continue that discussion in that post, rather then here.
The present question is to do with how those plots appear which seems to vary depending on the y-axis and plotting style, but it looks to be a computer issue(?) as this problem is not happening today. In this question, I am using a dataset that has been processed from a series of .wav files to provide an array where the frequency content (A) of each .wav file (t) is reported in 1 Hz bins (f).
hello Louise
could you confirm how your wav file names are labelled ? I created some dummy ones on my side but I have some trouble with extracting the usefull time information from the filenames
my file name is like : test.20210202151315.cut.wav (from
%format is xxxx.yyMMddHHmmss.cut.wav)
so far I understand the only info we need to plot is the seconds extracted from the file name ? and this will be the start time on each x axis
Yes that is the correct format. The first four digits are a serial number. It looks like you have 4 digits for year instead of 2? I would like to have the start time of each file in hhMMss. The spectrogram processes the data in second chunks, so that's why the plot at the moment has seconds on x axis, but we really only need one time (start time of wav file) at the start of each of group of chunks/spectrogram/wav files.
hello Louise
ok - i am getting closer to the solution now . Still have to figure out how o keep only the first X Tick
for the time being I stll have all seconds displayed
here we can see the X tick label is consistent with the filename (seconds)
my dummy wav files names are :
test.210201111815.cut.wav
test.210304161825.cut.wav
test.210407094535.cut.wav
so the first plot should have a X Tick starting with 15 s , the second plot 25 s , and the third one 35 s
%%%%%%%%%%%%%%%%%%%%%%%%
% directory={'X:\SoundTrap\Boats\wav\Noises\LTSA test\LTSA test batch'}; %folder where wav files are
% folder=char(directory);
folder= pwd;
fullfnames=dir(fullfile(folder,'*.wav')); %list all .wavs in folder
nFiles=numel(fullfnames);
%get fs of first (i.e. all) files in folder
firstfile=fullfile(folder,char(fullfnames(1,1).name));
[xbit,fs]=audioread(firstfile,[1 2]);
tlo=1.0;
% thi=114.0;
thi=3.0; % for my demo
nlo=fs*tlo; %multiply fs by tlo to get starting point
nup=fs*thi; %do the same for end point
nfft=1024; % for my demo
% nfft=16384;
overlap=nfft/2; %50% overlap
% window=16384;
window=hanning(nfft);
cal=176.4;
cal=power(10,cal/20); %calculate calibration value
t0=0;
dt=1;
for iFile = 1:3 %nFiles
fullfname = fullfnames(iFile).name;
%format is xxxx.yyMMddHHmmss.cut.wav
% you'll have to set/get/extract start-time for each spectrogram
fname=strsplit(fullfname,{'.'});
fname_st=fname(2);
fname_st=datenum(fname_st,'yyMMddHHmmss');
tStartstrings{iFile} = fname_st;% you'll have to set/get/extract start-time for each spectrogram
[xbit,fs]=audioread(fullfile(folder,fullfname), [nlo nup]); %read in wav
xbit=detrend(xbit); %remove DC offset
calxbit=xbit*cal; %apply calibration
%Perform FFT and plot:
[S,F,T,P] = spectrogram(calxbit,window,overlap,nfft,fs,'yaxis');
T=fname_st+datenum(seconds(T)); %start time of .wav file + seconds of each chunk to produce informative x-axis
sph(iFile) = subplot(1,nFiles,iFile);
h = pcolor(T,F,10*log10(P)); % Here you might want to add the start-time, t0, to T
hold on
set(h,'EdgeColor','none');
datetick('x','SS')
xlabel(fullfname(1:length(fullfname)-4));
ylabel('Frequency (Hz)');
end
hello Louise
so how are you today and what still do we need to do to reach the finish line ?
all the best
Hi Mathieu, I will try latest suggestion this afternoon and get back! Thanks!
Hi Mathieu, the aim was to have these spectrograms in a single plot. It looks like this maybe isn't possible. It is perhaps best to first of all calculate power spectral density of each individual file in 1Hz bins and then create an matrix where the first column is time (start time of each .wav) and the remaining columns are dB in 1Hz bins. Then you could plot multiple spectrograms with an informative x axis.
Hello Louise
this is a result with all spectrograms in one plot - the data are separated by zeros just to avoid any misinterpretation of the plot
of course the wav files should be sampled at the same sampling freq - but even in a different scenario we can find a fix fr that
of course I still need to figure out how to make the x axis labelling working - that is still work ahead
code so far :
% %% read multiple files
% fileDir = pwd; % currrent directory
%
% fileNames = dir(fullfile(fileDir,'*.wav')); % get list of files in directory
% fileNames_sorted = natsortfiles({fileNames.name}); % sort file names into order (https://fr.mathworks.com/matlabcentral/fileexchange/47434-natural-order-filename-sort)
% nFiles = numel(fileNames_sorted);
%
clc
clearvars
close all
%%%%%%%%%%%%%%%%%%%%%%%%
% directory={'X:\SoundTrap\Boats\wav\Noises\LTSA test\LTSA test batch'}; %folder where wav files are
% folder=char(directory);
folder= pwd;
fullfnames=dir(fullfile(folder,'*.wav')); %list all .wavs in folder
nFiles=numel(fullfnames);
%get fs of first (i.e. all) files in folder
firstfile=fullfile(folder,char(fullfnames(1,1).name));
[xbit,fs]=audioread(firstfile,[1 2]);
tlo=1.0;
% thi=114.0;
thi=3.0; % for my demo
nlo=fs*tlo; %multiply fs by tlo to get starting point
nup=fs*thi; %do the same for end point
nfft=1024; % for my demo
% nfft=16384;
overlap=nfft/2; %50% overlap
% window=16384;
window=hanning(nfft);
cal=176.4;
cal=power(10,cal/20); %calculate calibration value
t0=0;
dt=1;
P_all = [];
for iFile = 1:3 %nFiles
fullfname = fullfnames(iFile).name;
%format is xxxx.yyMMddHHmmss.cut.wav
% you'll have to set/get/extract start-time for each spectrogram
fname=strsplit(fullfname,{'.'});
fname_st=fname(2);
fname_st=datenum(fname_st,'yyMMddHHmmss');
tStartstrings{iFile} = fname_st;% you'll have to set/get/extract start-time for each spectrogram
[xbit,fs]=audioread(fullfile(folder,fullfname), [nlo nup]); %read in wav
xbit=detrend(xbit); %remove DC offset
calxbit=xbit*cal; %apply calibration
%Perform FFT and plot:
[S,F,T,P] = spectrogram(calxbit,window,overlap,nfft,fs,'yaxis');
P_all = [P_all P zeros(length(F),25)]; % concatenate all P data with some blanks in between
T=fname_st+datenum(seconds(T)); %start time of .wav file + seconds of each chunk to produce informative x-axis
end
[a,samples] = size(P_all);
t = (0:samples-1)*1/fs;
h = pcolor(t,F,10*log10(P_all)); % Here you might want to add the start-time, t0, to T
colormap(jet);
set(h,'EdgeColor','none');
datetick('x','SS')
title(fullfname(1:length(fullfname)-4));
xlabel('Time');
ylabel('Frequency (Hz)');

Sign in to comment.

Answers (0)

Categories

Products

Release

R2020a

Asked:

on 7 Oct 2021

Commented:

on 25 Oct 2021

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!