How to draw a rectangle around the area that shows an energy variation

7 ビュー (過去 30 日間)
Ricardo Duarte
Ricardo Duarte 2023 年 10 月 10 日
コメント済み: Mathieu NOE 2023 年 10 月 12 日
Hello all,
I have several wav files and I want to draw a rectangle around the area here a specific energy variation happend. Let's say, since the beggining til the end (in seconds)
In fact is something similar than the image attached
Thanks in advance for your help.
  3 件のコメント
Ricardo Duarte
Ricardo Duarte 2023 年 10 月 10 日
Thank you for your fast answering. In fact is both.
Dyuman Joshi
Dyuman Joshi 2023 年 10 月 10 日
編集済み: Dyuman Joshi 2023 年 10 月 10 日
Please attach the code and the data you are working with. Use the paperclip button to attach.
Also, specify the region around which you need to draw a rectangle.

サインインしてコメントする。

採用された回答

Star Strider
Star Strider 2023 年 10 月 10 日
It would help to have your data.
An adaptive approach using contour3
Fs = 500;
L = 300;
t = linspace(0, L*Fs, L*Fs+1)/Fs;
signal = sum(sin((100:50:200).'*2*pi*t) .* exp(-(t-150).^2*1E-3));
figure
plot(t, signal)
grid
xlabel('Time (s)')
ylabel('Amplitude')
[s,f,t,p] = spectrogram(signal,[],[],[],Fs); % Return Extra Outputs
figure
surf(f,t,p.')
colormap(turbo)
[h,c] = contour3(f,t,p.', 20); % Get Contours
Lvls = c.LevelList
Lvls = 1×20
0.5617 1.1235 1.6852 2.2470 2.8087 3.3705 3.9322 4.4940 5.0557 5.6175 6.1792 6.7409 7.3027 7.8644 8.4262 8.9879 9.5497 10.1114 10.6732 11.2349
ChooseLevel = 1;
idx = find(h(1,:) == Lvls(ChooseLevel));
for k = 1:numel(idx) % Get Contour (x,y) Coordinates
clen = h(2,idx(k));
x{k} = h(1,idx(k)+1:idx(k)+clen);
y{k} = h(2,idx(k)+1:idx(k)+clen);
end
[xmax,xmin] = bounds(cat(2,x{:})) % Extreme Values
xmax = 99.9763
xmin = 200.0246
[ymax,ymin] = bounds(cat(2,y{:})) % Extreme Values
ymax = 100.3145
ymin = 199.6891
colormap(turbo)
title('Contours')
figure
% spectrogram(signal,[],[],[],Fs)
surf(f,t,mag2db(p.'), 'EdgeColor','interp')
hold on
plot3([1 1]*xmin, [ymin ymax], [1 1]*Lvls(ChooseLevel), '-k', 'LineWidth',2)
plot3([xmin xmax], [1 1]*ymin, [1 1]*Lvls(ChooseLevel), '-k', 'LineWidth',2)
plot3([xmin xmax], [1 1]*ymax, [1 1]*Lvls(ChooseLevel), '-k', 'LineWidth',2)
plot3([1 1]*xmax, [ymin ymax], [1 1]*Lvls(ChooseLevel), '-k', 'LineWidth',2)
hold off
colormap(turbo)
view(0,90)
.
  4 件のコメント
Ricardo Duarte
Ricardo Duarte 2023 年 10 月 10 日
Perfect! Thank you @Star Strider, this solve the problem.
Star Strider
Star Strider 2023 年 10 月 10 日
As always, my pleasure!

サインインしてコメントする。

その他の回答 (2 件)

Mathieu NOE
Mathieu NOE 2023 年 10 月 10 日
hello
try this
IMO, the rectangle position is to be computed from your spectrogram results (define thresholds)
Fs = 1e3;
t=0:1/Fs:5; % 5 secs @ 1kHz sample rate
y=chirp(t,10,3,100,'q'); % Start @ 10Hz, cross 100Hz at t=3sec
% amplitude is increasing with time
y = y.*t./t(end);
[S,F,T] = spectrogram(y,hanning(128),64,128,Fs);
imagesc(T,F,20*log10(abs(S)));
caxis([-50 30]);
set(gca,'Ydir','normal');
colormap('jet');
colorbar('vert');
title('Quadratic Chirp: start at 100Hz and cross 200Hz at t=1sec');
xlabel('Time (s)')
ylabel('Frequency (Hz)')
% rectangle
fmin = 100;
fmax = 200;
tmin = T(end)/2;
tmax = T(end)*0.99;
rectangle('Position',[tmin fmin (tmax-tmin) (fmax-fmin)],'Curvature',0.25*[1 1],'Linewidth',3)
  3 件のコメント
Mathieu NOE
Mathieu NOE 2023 年 10 月 10 日
hello Ricardo
yes of course I suspected drawing the rectangle is not the issue here :)
here my new suggestion : assuming we can find the peak value of S , you can define a threshold (here 30 dB below the peak value (in dB)) so the rectangle is automatically drawn
you can change this threshold value in this line :
threshold = S_dB_max - 30; % define here threshold you want to draw the rectangle : here 30 dB below the peak amplitude (= S_dB_max)
full code
Fs = 1e3;
t=0:1/Fs:5; % 5 secs @ 1kHz sample rate
y=chirp(t,10,3,100,'q'); % Start @ 10Hz, cross 100Hz at t=3sec
% amplitude is changing with time
window = exp(-(t-3.5).^2/0.75); % gaussian window
y = y.*window;
[S,F,T] = spectrogram(y,hanning(128),64,128,Fs);
S_dB = 20*log10(abs(S));
S_dB_max = max(S_dB,[],'all');
threshold = S_dB_max - 30; % define here threshold you want to draw the rectangle : here 30 dB below the peak amplitude (= S_dB_max)
ind = S_dB>=threshold;
imagesc(T,F,S_dB);
caxis([-60 30]);
set(gca,'Ydir','normal');
colormap('jet');
colorbar('vert');
title('Quadratic Chirp');
xlabel('Time (s)')
ylabel('Frequency (Hz)')
% rectangle
indF = any(ind,2); % indices for F vector
indT = any(ind,1); % indices for T vector
fmin = min(F(indF),[],'all');
fmax = max(F(indF),[],'all');
tmin = min(T(indT),[],'all');
tmax = max(T(indT),[],'all');
rectangle('Position',[tmin fmin (tmax-tmin) (fmax-fmin)],'Curvature',0.25*[1 1],'Linewidth',3)
Mathieu NOE
Mathieu NOE 2023 年 10 月 12 日
huh, so my suggestion didn't please you ? (just kidding)

サインインしてコメントする。


Florian Bidaud
Florian Bidaud 2023 年 10 月 10 日
編集済み: Florian Bidaud 2023 年 10 月 10 日
Since you said your issue was both finding the variation and drawing the rectangle.
To find the variations, I would suggest using diff, and set a trigger value from which you decide this variation is interesting (that could be with a percentage from the others for example). This part, you need to think a bit about what variation is interesting.
Let's take the following example :
z = [1 3 5 6 11
1 3 6 5 8
1 2 3 9 7
1 1 2 3 6
1 1 1 2 4
];
zp = diff(z)
zp = 4×5
0 0 1 -1 -3 0 -1 -3 4 -1 0 -1 -1 -6 -1 0 0 -1 -1 -2
Here, if you set a limit of variation to 2, you can, for example find the x and y coordinate of your limits:
var_lim = 2;
x = find(sum(diff(z)<-var_lim),1)
x = 3
y = max(size(z))-find(sum(diff(z')>var_lim),1)
y = 4
Then from these, you can draw the rectangle as follows :
(in my case I chose 1 and 5 as I deal with indexes from 1 to 5, but this should be replace by your own limits on the plot)
f = figure;
hold on
s = surf(z);
p = plot([x 5 5 x x],[1 1 y y 1]);
p.ZData = [50 50 50 50 50]; %to put it on top
p.Color = 'black';
p.LineWidth = 3;
f.Children.View = [0 90];

カテゴリ

Help Center および File ExchangeJust for fun についてさらに検索

製品

Community Treasure Hunt

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

Start Hunting!

Translated by