[Scilab-users] spectrogram
Federico Miyara
fmiyara at fceia.unr.edu.ar
Mon Jul 12 01:21:40 CEST 2021
Dear All,
I noticed there is no spectrogram function in Scilab that provides both
graphic and numerical output. There is a function mapsound(), which
plots a spectrogram without numerical information and without control
over important aspects such has FFT length or windowing function. By the
way, in the field of digital sound processing the usual name for this is
spectrogram, not mapsound, which is a bit confusing.
I created a spectrogram() function. Even if it doesn't yet comply with
the recommended style for Scilab functions (particularly regarding error
handling or manual page), I think it might be useful for some users. I
attach the function and a test script.
Regards,
Federico Miyara
--
El software de antivirus Avast ha analizado este correo electrónico en busca de virus.
https://www.avast.com/antivirus
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.scilab.org/pipermail/users/attachments/20210711/f91d090b/attachment.htm>
-------------- next part --------------
function [z, t, f] = spectrogram(x, N, Fs, M, w, grph)
// Spectrogram of a signal
//
// Usage
// [z, t, f] = spectrogram(x, N, Fs, M, w, grph)
// where
// x: signal vector
// Fs: sample rate in Hz
// N: FFT window length
// Fs: sample rate in Hz
// M: offset between FFT windows in samples
// w: windowing function; accepted values are
// "boxcar", "hann", "hamming", "blackman",
// "bharris", "flattop" and a custom vector
// containing N components of the window
// grph: graphic output; accepted values are
// "lin", "lincmap", "log", "logcmap",
// lin/log refers to linear or logarithmic
// distribution of magnitude along the
// colormap and cmap to the inclusion or
// not of a colormap. The default is no
// graph.
// z: matrix with N/2 rows and
// floor((length(x) - N)/M + 1) columns,
// where each column contains the absolute
// value of the spectrum beginning at each
// multiple of M
// t: vector containing starting times in s of
// each FFT window
// f: vector containing the values of the
// FFT frequency bins in Hz
//
// -----------------------------------------------
// Author: Federico Miyara
// Date: 2021-07-10
// Argument handling
rhs = argn(2);
if rhs<6
grph = [];
end
if rhs<5
w = "hann";
end
if rhs<4
M = 512;
end
if rhs<3
Fs = 44100;
end
if rhs<2
N = 1024;
end
// Data for testing purpooses --DELETE--
if 1==2
Fs = 44100
N = 1024
M = 256
w = "hann"
grph = "logcmap"
tt = 0:1/Fs:2;
fo = 8000
fm = 0.5
df = 4000
ff = fo + df*sin(2*%pi*fm*tt);
phi = 2*%pi*cumsum(f)/Fs;
caso = 2
select caso
case 1
x = 0.4*sin(phi) + 0.3*sin(2*phi);
case 2
x = sin(phi) + sin(2*phi);
x = min(x, ones(x));
end
wavwrite(x,"d:\hola\fmod.wav")
end
// Ensure the signal is a column vector
x = x(:);
// Number of FFT windows
Q = floor((length(x) - N)/M + 1);
// Initialize z
z = zeros(N/2, Q);
// Generate a matrix whose columns are
// segments with length N of the signal
// starting at sample indices multiple
// of M
y = zeros(N, Q);
for k=1:Q
y(:,k) = x((k-1)*M+1:(k-1)*M+N);
end
// Compute window function
if type(w)==1
w = w(:);
else
select w
case "boxcar"
w = 1;
case "hann"
w = 0.5 - 0.5*cos(2*%pi*[0:N-1]/N)';
case "hamming"
w = 0.54 - 0.46*cos(2*%pi*[0:N-1]/N)';
case "blackman"
w = 0.42 - 0.5*cos(2*%pi*[0:N-1]/N)' + ...
0.08*cos(4*%pi*[0:N-1]/N)';
case "bharris"
w = 0.35875 - 0.48829*cos(2*%pi*[0:N-1]/N)' + ...
0.14128*cos(4*%pi*[0:N-1]/N)' - ...
0.01168*cos(6*%pi*[0:N-1]/N)';
case "flattop"
wft = 1 - 1.90796*cos(2*%pi*[0:N-1]/N)' + ...
1.07349*cos(4*%pi*[0:N-1]/N)' - ...
0.18199*cos(6*%pi*[0:N-1]/N)';
end
end
// Replicate window
ww = repmat(w, 1, Q);
// FFT of the windowed signal along columns
// and conversion to unilateral spectrum
z = abs(fft(y.*ww, -1, 1))(1:N/2,:)*2/N;
z(1,:) = z(1,:)/2;
// Starting times of the FFT windows
t = (0:Q-1)*M/Fs;
// Frequencies of the FFT bins
f = (0:N/2-1)*Fs/N;
// Graphic output
cmap = jetcolormap(64);
select grph
case "lin"
figure();
clf();
gcf().color_map= [cmap; [1 1 1]];
gcf().background = 65;
Sgrayplot(t, f, z');
case "lincmap"
figure();
clf();
gcf().color_map= [cmap; [1 1 1]];
gcf().background = 65;
Sgrayplot(t, f, z');
colorbar
case "log"
figure()
clf();
gcf().color_map= [cmap; [1 1 1]];
gcf().background = 65;
Sgrayplot(t, f, 20*log10(z'));
case "logcmap"
figure()
clf();
gcf().color_map= [cmap; [1 1 1]];
gcf().background = 65;
Sgrayplot(t, f, 20*log10(z'));
colorbar
end
endfunction
-------------- next part --------------
// Testing the function spectrogram()
// Sample rate i Hz
Fs = 44100
// Size of FFT window
N = 1024
// Ofset in samples between FFT windows
M = 256
// Tapering window function
w = "hann"
// Type of graphic output
grph = "logcmap";
// Time vector in s
t = 0:1/Fs:2;
// Carrier frequency in Hz
fo = 8000
// Modulation frequency in Hz
fm = 0.5
// Frequency deviation in Hz
df = 4000
// Frequency vector
f = fo + df*sin(2*%pi*fm*t);
// Phase computed by numerical integration
phi = 2*%pi*cumsum(f)/Fs;
// Signal generation
caso = 2
select caso
case 1
// Two harmonics with aliasing
x = 0.4*sin(phi) + 0.3*sin(2*phi);
case 2
// Two harmonics with aliasing and distortion
// by truncation
x = sin(phi) + sin(2*phi);
x = min(x, ones(x));
end
// Save wave as a wav file to compare with external
// software such as Audacity
//wavwrite(x,"d:\hola\fmod.wav")
exec spectrogram.sci
z = spectrogram(x, N, Fs, M, w, grph);
More information about the users
mailing list