Background
Magnitude MRI data has Rician noise distribution by definition ((Hákon Gudbjartsson and Samuel Patz, “The Rician Distribution of Noisy MRI Data,” Magnetic resonance in medicine : official journal of the Society of Magnetic Resonance in Medicine / Society of Magnetic Resonance in Medicine 34, no. 6 (December 1995): 910-914)). It comes about because two channels each with Gaussian noise are squared and added together ((R M Henkelman, “Measurement of signal intensities in the presence of noise in MR images,” Medical Physics 12, no. 2 (April 1985): 232-233.)). There is a longer description here.
Modeling
The Rician noise is created as $latex y_e(t_i) = \sqrt{ \left[y(t_i) + e_1 \right]^2 + e_2^2 }$, where $latex y$ is the true signal, and $latex e_1$ and $latex e_2$ are random numbers from a Gaussian distribution with zero mean and standard deviation $latex \sigma$. The standard deviation, $latex \sigma$, for the Gaussian distribution is related to the signal to noise ratio and is typically on the order of 1% – 10% of the signal $latex y$.
Code
It is relatively easy to model this using Matlab or Python. For the code here I am modeling a T2 decay curve and then the noise.
Matlab
[cc lang="matlab"]
% Setup the initial variables
rho = 100;
t2 = 80; % in ms
te = 10:10:320; % in ms
% Create a T2 decay curve
y = rho * exp(-te / t2 );
% Define the noise to be 5% of the signal
s = 5;
% Create the two Gaussian random variable vectors
e1 = s * randn(size(y));
e2 = s * randn(size(y));
% Now create the new, noisy decay curve.
y_e = sqrt( (y+e1).^2 + (e2).^2 );
[/cc]
Python
The Python version is quite similar.
[cc lang="python"]
from __future__ import division
# Setup the initial variables
rho = 100
t2 = 80 # in ms
te = r_[10:330:10] # in ms
# Create a T2 decay curve
y = rho * exp( -te / t2 )
# Define the noise to be 5% of the signal
s = 5;
# Create the two Gaussian random variable vectors
e1 = normal(0, 5, y.shape)
e2 = normal(0, 5, y.shape)
# Now create the new, noisy decay curve.
y_e = sqrt( (y+e1)**2 + (e2)**2 );
[/cc]
There are a couple of small gotcha’s that at least tripped me up as I am still relatively new to Python.
- The first is that under Python 2.x all data is processed as integer (not doubles, as the default is in Matlab). Supposedly this is going to change in Python 3, but to get around it for now, the best thing to do is to add the [cci lang="python"]from __future__ import divison[/cci].
- To define [cci lang="python"]te[/cci] I had to go to 330, rather than 320 as the generator is an open set on the higher end so it does not include the number.
- There are several options for creating the random numbers. There is a Python module called [cci lang="python"]random[/cci] that could be used. Instead I used the Numpy [cci lang="python"]normal[/cci] instead as I can pass in the shape parameter.