Nano Particles

Random project notes.
Author

Sjoerd de Haan

Published

January 1, 2025

Nano Particles

We use the following file:

[1] "../../results/data/raw/fukuda/AuNP1NR9_unfil_500_pseudo.csv"

Questions

  1. Can we distinguish the particles without deep learning?
  2. Are the jumps normally distributed?
First 10 steps or particle 1
particle step x y x_prev y_prev dx dy ddx ddy jump_angle
1 1 0.0626 -0.241
 NA
NA
 NA
 NA
 NA
 NA
NA
1 2 -0.3609 0.322 0.0626 -0.241 -0.4234 0.5635
 NA
 NA
NA
1 3 -0.1698 -0.161 -0.3609 0.322 0.1911 -0.4831 0.6145 -1.0466 8.84
1 4 0.0663 -0.610 -0.1698 -0.161 0.2361 -0.4493 0.0451 0.0337 99.09
1 5 0.0513 -0.457 0.0663 -0.610 -0.0151 0.1528 -0.2512 0.6021 17.01
1 6 0.4158 0.290 0.0513 -0.457 0.3645 0.7473 0.3796 0.5946 6.55
1 7 0.2231 0.323 0.4158 0.290 -0.1927 0.0331 -0.5572 -0.7142 61.80
1 8 0.0989 0.589 0.2231 0.323 -0.1242 0.2656 0.0684 0.2324 41.48
1 9 -0.5910 0.102 0.0989 0.589 -0.6899 -0.4864 -0.5656 -0.7520 17.86
1 10 -0.2061 0.688 -0.5910 0.102 0.3849 0.5853 1.0747 1.0717 11.75

Trajectories

Jumps

Jumps in the x-direction do not follow a normal distribution.

If we look at single particles, it seems the do follow a normal distribution.

Particle positions

`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

Scale per tarjectory

# A tibble: 0 × 2
# ℹ 2 variables: particle <int>, v <dbl[,1]>

# A tibble: 1 × 4
  `var(x)`[,1] `var(y)`[,1] `mean(x)` `mean(y)`
         <dbl>        <dbl>     <dbl>     <dbl>
1        0.990        0.990 -6.74e-20  7.10e-19

# A tibble: 11 × 4
   particle  step  x[,1] y[,1]
      <int> <int>  <dbl> <dbl>
 1       19    97  4.97  -4.11
 2       26    72 -0.374 -4.11
 3      123    18 -1.81  -5.06
 4      129    82 -2.54  -5.07
 5      143    77  1.74  -5.63
 6      205    10 -0.913 -4.00
 7      289     1 -0.429 -5.29
 8      332    98  1.69  -4.09
 9      411    26 -1.56  -4.17
10      475    45  4.54  -4.48
11      476    60 -1.32  -4.55

{r setup, include=FALSE} knitr::opts_chunk$set(echo = FALSE, cache = TRUE, warning = FALSE) library(tinytable) options(digits = 3) # how many significant digits to print by default options("tinytable_tabularray_placement" = "H") # for LaTeX source("single-particle-tracking.R")

We we obtained a dataset of nano particle suspended in water in water, undergoing Brownian motion. The movements of the particles was tracked with a high speed camera [@fukudaAnalysisBrownianMotion2023], at 100 frames per second.

500 particles were tracked for a duration of 1 second.

Experimental setup

Each tracked particle has 100 jumps recorded at intervals of 10 ms[1]. Distance traveled between frames is recorded in a 2D plane wi

We make a couple of simplifying assumptions

  • An individual particle is tracked for the entire duration of the experiment.
  • The fluid is still, and the particles are not subject to any external forces.
  • The space is isotropic
  • The coordinates system for the measurement is orthogonal

Trajectories

The data looks like this:

#| label: trajectories
#| tbl-cap: "First 10 steps or particle 1"
jumps <- read_jumps(DATA_FILE)
trajectories <- add_trajectories(jumps)
trajectories |>
  head(10) |>
  tt()

We integrate the jumps to obtain 500 trajectories. As the abosulute positions are not included in the dataset, we lose this information.

The units of measurement are misisng in the article; they may be in denoted μm.

plot_trajectory(trajectories, 1)

Jumps

Jumps in the x-direction do not follow a normal distribution.

{r pressure, echo=FALSE} plot_normal_qq(trajectories, dx)

If we look at single particles, it seems the do follow a normal distribution.

trajectories |>
  filter(particle == 4) |>
  plot_normal_qq(dx)
simulate_plot_jumps(99)

Particle positions

stats <- 
  trajectories |> 
  stats_per_particle()
plot_mean_particle_positions(stats)


average_plot <- stats |>
  ggplot(aes(x=x_mean, y=y_mean)) +
    geom_point(color=BLUE) +
    labs(
      title = "Average position",
      x = "x",
      y= "y",
    ) 

The trajectories are centered around the origin.

average_plot +
    geom_line(data = trajectories, aes(x=x, y=y), color=GRAY, alpha=0.4) +
    labs(
      title = "Mean positions + trajectories",
      x = "x",
      y= "y",
      group="particle",
    ) 
stats |>
  plot_variance_histogram(x_var)
stats |>
  plot_variance_histogram(y_var)

Scale per tarjectory

Here we normalize the trajectories per particle, to have variance 1.

trajectories_scaled <-
  trajectories |>
  select(particle, step, x, y) |>
  group_by(particle) |>
  # Scaling and centring
  mutate(across(c(x, y), scale)) |>
  ungroup()
trajectories_scaled |>
  ggplot(aes(sample = y)) +
    geom_qq(size = 1, alpha = 1, color=BLUE) +
    geom_qq_line() +
    geom_qq(aes(sample = x), size = 1, alpha = 1, color=RED) 
simulate_plot_jumps(500 * 100)
trajectories_scaled |>
  group_by(particle) |>
  summarise(v = var(y)) |>
  filter(abs(v- 1) > 0.0001)
trajectories_scaled |>
  summarise(var(x), var(y), mean(x), mean(y))
trajectories_scaled |>
  filter(y < -4) |>
  arrange(particle)

Units

New

  • \(\um\)

[1] [@fukudaAnalysisBrownianMotion2023] speak of one second. The actual data contains 100 jumps; spanning a time of 110ms.