Modifying noise intensity by different SNR - signal-processing

I was trying out the signal process library ThinkDSP.
My desired operation is to add some noise on the original .wav file
I've known that this operation is easy to achieve by add_noise = my_wav + noise
However, I would like to modify the noise under different SNR conditions
How do I achieve this by ThinkDSP? Or other methods are also welcome. Thank you.

You need to calculate the power in your wav file and determine the noise power that will give you the desired snr. In Python with scipy this is quite easy.
# Import scipy
import scipy as sp
# Signal power in data from wav file
psig = sig.var()
# For 10 dB SNR, calculate linear SNR (SNR = 10Log10(Psig/Pnoise)
snr_lin = 10.0**(10.0/10.0)
# Find required noise power
pnoise = psig/snr_lin
# Create noise vector
noise = sp.sqrt(pnoise)*sp.randn(len(sig))
# Add noise to signal
sig_plus_noise = sig + noise
See this answer for more information Add random noise with specific SNR to a signal

Related

Using ICA over MIT BIH NST dataset

In this dataset, I wanted to use signals with same unit and different SNR as input signals in ICA, i.e.
ica_input = np.array([ record_118e_6(MLII),
record_118e00(MLII),
record_118e06(MLII),
record_118e12(MLII),
record_118e18(MLII)
])
Is this a correct input to ICA?
Can I here consider the signal with different SNR linear mix of noises and true signal?
According to this article (which states how the dataset is generated by nst), The above input channels are linear mix of noise and clean signal and from plotting one can see that this data is clearly non gaussian hence ICA can be used in this case. Please correct me if I am wrong.

How to apply low-pass filter to a sound record on python?

I have to reduce white noise from a sound record.Because of that i used fourier transform.But i dont know how to use the fft function's return values which is in frequincy domain.How can i use the fft data to reduce noise?
Here is my code
from scipy.io import wavfile
import matplotlib.pyplot as plt
import simpleaudio as sa
from numpy.fft import fft,fftfreq,ifft
#reading wav file
fs,data=wavfile.read("a.wav","wb")
n=len(data)
freqs=fftfreq(n)
mask=freqs>0
#calculating raw fft values
fft_vals=fft(data)
#calculating theorical fft values
fft_theo=2*np.abs(fft_vals/n)
#ploting
plt.plot(freqs[mask],fft_theo[mask])
plt.show()```
It is better for such questions to build a synthetic example, so you don't have to post a big datafile and people can still follow your question (MCVE).
It is also important to plot intermediate results since we are talking about operations on complex numbers, so we often have to take re, im parts, or absolutes and angles respectively.
The Fourier transform of a real function is complex but is symmetric for positive vs negative frequencies. One can also look at that from an information theoretical viewpoint: you wouldn't want N independent real numbers in time to result in 2N independent real numbers describing the spectrum.
While you normally plot the absolute or absolute squared (voltage vs. power) of the spectrum, you can leave it complex when you apply the filter. After back-conversion to time via the IFFT, to plot it, you'll have to convert it to a real number again, in this case by taking the absolute.
If you design the filter kernel in the time domain (FFT of a Gaussian will be a Gaussian), the IFFT of the product of the FFT of the filter and the spectrum will have only very small imaginary parts and you can then take the real part (which makes more sense from a physics viewpoint, you started with real part, end with real part).
import numpy as np
import matplotlib.pyplot as p
%matplotlib inline
T=3 # secs
d=0.04 # secs
n=int(T/d)
print(n)
t=np.arange(0,T,d)
fr=1 # Hz
y1= np.sin(2*np.pi*fr*t) +1 # dc offset helps with backconversion, try setting it to zero
y2= 1/5*np.sin(2*np.pi*7*fr*t+0.5)
y=y1+y2
f=np.fft.fftshift(np.fft.fft(y))
freq=np.fft.fftshift(np.fft.fftfreq(n,d))
filter=np.exp(- freq**2/6) # simple Gaussian filter in the frequency domain
filtered_spectrum=f*filter # apply the filter to the spectrum
filtered_data = np.fft.ifft(filtered_spectrum) # then backtransform to time domain
p.figure(figsize=(24,16))
p.subplot(321)
p.plot(t,y1,'.-',color='red', lw=0.5, ms=1, label='signal')
p.plot(t,y2,'.-',color='blue', lw=0.5,ms=1, label='noise')
p.plot(t,y,'.-',color='green', lw=4, ms=4, alpha=0.3, label='noisy signal')
p.xlabel('time (sec)')
p.ylabel('amplitude (Volt)')
p.legend()
p.subplot(322)
p.plot(freq,np.abs(f)/n, label='raw spectrum')
p.plot(freq,filter,label='filter')
p.xlabel(' freq (Hz)')
p.ylabel('amplitude (Volt)');
p.legend()
p.subplot(323)
p.plot(t, np.absolute(filtered_data),'.-',color='green', lw=4, ms=4, alpha=0.3, label='cleaned signal')
p.legend()
p.subplot(324)
p.plot(freq,np.abs(filtered_spectrum), label = 'filtered spectrum')
p.legend()
p.subplot(326)
p.plot(freq,np.log( np.abs(filtered_spectrum)), label = 'filtered spectrum')
p.legend()
p.title(' in the log plot the noise is still visible');

How to source localize resting state MEG data with no events and epochs using python-MNE

While performing source localization of MEG resting stage data it ask for epochs and events which I do not have in my data set as it is a resting state data. It is also preprocessed.
MNE-Python can do source location for continuous (Raw) data. You just need to think what to use to compute the noise covariance. For resting state data, a good choice for noise covariance is a piece of empty room data. Here is an example using the sample dataset that ships with MNE-Python:
import mne
# Load the sample data
path = mne.datasets.sample.data_path()
raw = mne.io.read_raw_fif(path + '/MEG/sample/sample_audvis_raw.fif', preload=True)
# Make a noise covariance matrix using empty room data
empty_room = mne.io.read_raw_fif(path + '/MEG/sample/ernoise_raw.fif', preload=True)
noise_cov = mne.compute_raw_covariance(empty_room, tmin=0, tmax=None)
# Load the leadfield (=forward operator)
fwd = mne.read_forward_solution(path + '/MEG/sample/sample_audvis-meg-oct-6-fwd.fif')
# Make the inverse operator
inv = mne.minimum_norm.make_inverse_operator(raw.info, fwd, noise_cov)
# Compute MNE source estimate for the continuous resting state data. The result
# is a huge matrix, so let's downsample the original raw a bit.
raw.resample(100) # Downsample to 100 Hz
resting_state = mne.minimum_norm.apply_inverse_raw(raw, inv, lambda2=1E-4)

Using RNN to recover sine wave from noisy signal

I am involved with an application that needs to estimate the state of a certain system in real time by measuring a set of (non-linearly) dependent parameters. Up until now the application was using an extended Kalman filter, but it was found to be underperforming in certain circumstances, which is likely caused by the fact that the differences between the real system and its model used in the filter are too significant to be modeled as white noise. We cannot use a more precise model for a number of unrelated reasons.
We decided to try recurrent neural networks for the task. Since my experience with neural networks is quite limited, before tackling the real task itself, I decided to practice with a hand crafted problem first. That problem, however, I could not solve, so I'm asking for help here.
Here's what I did: I generated some sine waveforms of varying phase, frequency, amplitude, and offset. Then I distorted the waveforms with some white noise, and (unsuccessfully) attempted to train an LSTM network to recover my waveforms from the noisy signal. I expected that the network will eventually learn to fit a sine waveform into the noisy data set.
Here's the source (slightly abridged, but it should work):
#!/usr/bin/env python3
import time
import numpy as np
from keras.models import Sequential
from keras.layers import Dense, LSTM
from keras.layers.wrappers import TimeDistributed
from keras.objectives import mean_absolute_error, cosine_proximity
POINTS_PER_WF = int(1e4)
X_SPACE = np.linspace(0, 100, POINTS_PER_WF)
def make_waveform_with_noise():
def add_noise(vec):
stdev = float(np.random.uniform(0.01, 0.2))
return vec + np.random.normal(0, stdev, size=len(vec))
f = np.random.choice((np.sin, np.cos))
wf = f(X_SPACE * np.random.normal(scale=5)) *\
np.random.normal(scale=5) + np.random.normal(scale=50)
return wf, add_noise(wf)
RESCALING = 1e-3
BATCH_SHAPE = (1, POINTS_PER_WF, 1)
model = Sequential([
TimeDistributed(Dense(5, activation='tanh'), batch_input_shape=BATCH_SHAPE),
LSTM(20, activation='tanh', inner_activation='sigmoid', return_sequences=True),
LSTM(20, activation='tanh', inner_activation='sigmoid', return_sequences=True),
TimeDistributed(Dense(1, activation='tanh'))
])
def compute_loss(y_true, y_pred):
skip_first = POINTS_PER_WF // 2
y_true = y_true[:, skip_first:, :] * RESCALING
y_pred = y_pred[:, skip_first:, :] * RESCALING
me = mean_absolute_error(y_true, y_pred)
cp = cosine_proximity(y_true, y_pred)
return me + cp
model.summary()
model.compile(optimizer='adam', loss=compute_loss,
metrics=['mae', 'cosine_proximity'])
NUM_ITERATIONS = 30000
for iteration in range(NUM_ITERATIONS):
wf, noisy_wf = make_waveform_with_noise()
y = wf.reshape(BATCH_SHAPE) * RESCALING
x = noisy_wf.reshape(BATCH_SHAPE) * RESCALING
info = model.train_on_batch(x, y)
model.save_weights('final.hdf5')
The first dense layer is actually useless, the reason I added it is because I wanted to make sure I can successfully combine LSTM and time distributed dense layers, since my real application will likely need that setup.
The error function was modified a number of times. Initially I was using plain mean squared error, but the training process was extremely slow, and it was mostly converging to simply copying the input noisy signal into the output. The cosine proximity metric I added later essentially defines the degree of similarity between the shapes of the functions; it seemed to speed up the learning quite a bit. Also note that I'm applying the loss function only to the last half of the dataset; the motivation for that is that I expected that the network will need to see a few periods of the signal in order to be able to correctly identify the parameters of the waveform. However, I found that this modification has no visible effect on the performance of the network.
The latest modification of the script uses Adam optimizer, I also experimented with RMSProp with varying learning rate and decay settings, but I found no noticeable difference in behavior of the network.
I am using Theano 0.9 (dev) backend configured to use 64 bit floating point, in order to prevent possible issues with numerical stability. The epsilon value is set accordingly to 1e-14.
This is what the output looks like after 15k..30k training steps (performance stops improving starting from about 15k steps) (the first plot is zoomed in for the sake of clarity):
Plot legend:
blue (0) - noisy signal, input of the RNN
green (1) - recovered signal, output of the RNN
red (2) - ground truth
My question is: what am I doing wrong?

Why are my TensorFlow network weights and costs NaN when I use RELU activations?

I can't get TensorFlow RELU activations (neither tf.nn.relu nor tf.nn.relu6) working without NaN values for activations and weights killing my training runs.
I believe I'm following all the right general advice. For example I initialize my weights with
weights = tf.Variable(tf.truncated_normal(w_dims, stddev=0.1))
biases = tf.Variable(tf.constant(0.1 if neuron_fn in [tf.nn.relu, tf.nn.relu6] else 0.0, shape=b_dims))
and use a slow training rate, e.g.,
tf.train.MomentumOptimizer(0.02, momentum=0.5).minimize(cross_entropy_loss)
But any network of appreciable depth results in NaN for cost and and at least some weights (at least in the summary histograms for them). In fact, the cost is often NaN right from the start (before training).
I seem to have these issues even when I use L2 (about 0.001) regularization, and dropout (about 50%).
Is there some parameter or setting that I should adjust to avoid these issues? I'm at a loss as to where to even begin looking, so any suggestions would be appreciated!
Following He et. al (as suggested in lejlot's comment), initializing the weights of the l-th layer to a zero-mean Gaussian distribution with standard deviation
where nl is the flattened length of the the input vector or
stddev=np.sqrt(2 / np.prod(input_tensor.get_shape().as_list()[1:]))
results in weights that generally do not diverge.
If you use a softmax classifier at the top of your network, try to make the initial weights of the layer just below the softmax very small (e.g. std=1e-4). This makes the initial distribution of outputs of the network very soft (high temperature), and helps ensure that the first few steps of your optimization are not too large and numerically unstable.
Have you tried gradient clipping and/or a smaller learning rate?
Basically, you will need to process your gradients before applying them, as follows (from tf docs, mostly):
# Replace this with what follows
# opt = tf.train.MomentumOptimizer(0.02, momentum=0.5).minimize(cross_entropy_loss)
# Create an optimizer.
opt = tf.train.MomentumOptimizer(learning_rate=0.001, momentum=0.5)
# Compute the gradients for a list of variables.
grads_and_vars = opt.compute_gradients(cross_entropy_loss, tf.trainable_variables())
# grads_and_vars is a list of tuples (gradient, variable). Do whatever you
# need to the 'gradient' part, for example cap them, etc.
capped_grads_and_vars = [(tf.clip_by_value(gv[0], -5., 5.), gv[1]) for gv in grads_and_vars]
# Ask the optimizer to apply the capped gradients.
opt = opt.apply_gradients(capped_grads_and_vars)
Also, the discussion in this question might help.

Resources