In digital signal processing it can be useful to boost frequencies in the signal at a certain time. For example, it can be used to compensate for the diispation of sound in the medium.
To know what frequencies are present in the signal mathematicians usually use the Fourier transform.
Or its discrete variant
But the Fourier transform only tells you what frequencies are present in the entire signal.
To know what frequencies are present in a short time frame, the signal is split into regions using a window function and then the Fourier transform is applied. This transformation is called short-time Fourier Transform(STFT) and the tranform of a discrete signal is called STFT matrix.
Where:
Here is a python STFT implementation using numpy. Please note the padding the signal to the nearest integer number of windows.
def stft(signal, nperseg, noverlap): window = np.hanning(nperseg) window_step = nperseg - noverlap right_padding = window_step * int(len(signal) / window_step + 1) - len(signal) signal= np.pad(signal, (window_step, right_padding), 'constant', constant_values=(0, 0)) windows = [signal[i:i+nperseg] * window for i in range(0, len(signal) - window_step, window_step)] spectrogram = [np.fft.rfft(win) for win in windows] return np.array(spectrogram).T
The STFT is invertable, so the signal can be reconstructed from its STFT matrix. This allows us to modify frequencies of the signal at a certain time window. But not every STFT matrix has a real corresponding signal. A naive implementation of the inverse STFT of a modified STFT matrix can result in discontinuity at the windows’ borders.
The estimation of the signal obtained by minimizing the error is decribed in the IEEE paper by Griffin et al.
Here’s a simple python implementation of the algorithm:
def istft(spectogram, nperseg, noverlap): window = np.hanning(nperseg) window_step = nperseg - noverlap signal_len = (spectogram.shape[1] + 1) * window_step x = np.zeros(signal_len) norm = np.zeros(signal_len) for n, i in enumerate(range(0, signal_len - window_step, window_step)): x[i:i+nperseg] += np.real(np.fft.irfft(spectogram[:, n])) * window norm[i:i+nperseg] += window * window x /= np.where(norm > 1e-10, norm, 1.0) return x[window_step:]