When implementing the vanilla algorithm of Vicsek model from Vicsek’s 1995 PRL paper in 3D, one need to rotate a lot of vectors. This post introduced my idea of generating such noise.


2D and 3D

In the original paper, the noise is implemented by rotating the targeted direction by a random direction. I find the math equation in this paper being very good addressing such process, as the following.

\[\mathbf{s}_{i}^{t+\Delta t}=\mathcal{R}_{\eta}\left[\frac{\sum_{j} n_{i j}^{t} \mathbf{s}_{j}^{t}}{\left\|\sum_{j} n_{i j}^{t} \mathbf{s}_{j}^{t}\right\|}\right]\]

The operator $\mathcal{R}_\eta(\mathbf{s})$ is responsible for rotating vector $\mathbf{s}$ around for a magnitude of $\eta$ randomly.

In the 2D case, if the angle of vector $\mathbf{s}$ is $\theta$, then the operator $\mathcal{R}_\eta(\mathbf{s})$ actually does this.

\[\theta \rightarrow \theta + \text{U}(-\pi \eta, \pi\eta)\]

where $U$ corresponds to a uniform distribution.

In 3D however, things are getting tricker. The following graph shows the effect of $\mathcal{R}_\eta$. The desired effect is to rotate angle $s$ randomly inside the pink region.

The next chapter will discuss the way to perform this operation.

Generating 3D noise

The practical way to generate scalar noise in 3D is this,

  1. Generate uniformly distributed noise as if vector $\mathbf{s}$ is (0, 0, 1).
  2. Rotate the generated noise to the direction of $\mathbf{s}$

Random Vectors

The aim is to generate random vectors pointing uniformly to the pink cap.

The python code that generating such noise is this

noise_phi = np.random.uniform(-np.pi, np.pi, N)
noise_z = np.random.uniform(1 - 2 * eta, 1, N)
noise_r = np.sqrt(1 - noise_z**2)
noise_x = noise_r * np.cos(noise_phi)
noise_y = noise_r * np.sin(noise_phi)
noise = np.array((noise_x, noise_y, noise_z)).T

The not very obvious code is this line.

noise_z = np.random.uniform(1 - 2 * eta, 1, N)

Here, $\eta$ (eta) is a measure of noise level ranging from $0$ to $1$. When $\eta = 1$ the pink cap would be the entire unit sphere, and the cap will vanish if $\eta = 0$.

Embarrassingly I learned how to pick up points on a sphere just recently at the age of 28, with this extremely helpful stackexchange answer. Basically the idea is if I need the uniform distribution on the pink cap, I will need two uniform distributions.

\[\begin{aligned} \theta &\sim \text{U}(-\pi, \pi)\\ z &\sim \text{U}(1-h, 1)\\ &\sim \text{U}(1-2\eta, 1) \end{aligned}\]

The relationship between $\eta$ (eta) and $h$, $h \sim 2\eta$, comes from the area of the pink cap inside a unit sphere.

\[2 \pi h\]

where $h$ takes the range between $0$ and $2$.

Rotation

Now we have noise vectors around $\mathbf{s}’$, the next step is to find a rotation matrix $\mathbf{R}$ that performs the following transformation.

\[\bf{s = R \cdot s'}\]

following this stackexchange answer, it is intuitive to break the rotation into the following parts.

  1. Transform the basis from $\bf{(x, y, z)}$ to $\bf{(u, v, w)}$.
  2. Perform a simple rotation.
  3. Transform back from $\bf{(u, v, w)}$ to original basis $\bf{(x, y, z)}$.

The key observation to calculate this rotation is that such rotation is very straightforward in the following $\bf{(u, v, w)}$ basis. It is merely a rotation along $\bf{w}$ axis.

The rotation angle $\theta$ in the $\bf(u,v,w)$ basis is calculated by $\arccos(\bf{s \cdot s’})$, and the rotation matrix is simply this.

\[\begin{pmatrix} \cos\theta & -\sin\theta & 0\\ \sin\theta & \cos\theta & 0\\ 0 & 0 & 1 \end{pmatrix}\]

A step-by-step operation tutorial is in this stackexchange answer.