Calculating surface roughness¶

This notebook levels an image of sapphire and calculates its roughness: the areal parameters of ISO 25178, the height distribution, the power spectrum, and the roughness along a single line. Run it from this folder, next to sapphire.nid.

In [1]:
from NSFopen.process import process

import matplotlib.pyplot as plt
In [2]:
afm = process("sapphire.nid")
afm.flatten(order=1)  # subtract a line from every scan line

fig = afm.image(color_range="p1")
plt.show()
No description has been provided for this image

Surface parameters¶

statistics() returns a table with values and units. The values are in SI units. Sku follows ISO 25178, so it is 3 for a Gaussian surface.

In [3]:
table = afm.statistics()
print(table)
                           value unit
Pixels              6.553600e+04     
Area                6.250000e-12   m²
Mean               -2.007722e-22    m
Median              3.769956e-13    m
Min                -1.735707e-10    m
Max                 1.693604e-10    m
Sa                  3.357276e-11    m
Sq                  4.212310e-11    m
Ssk                -5.643154e-02     
Sku                 3.010210e+00     
Sp                  1.693604e-10    m
Sv                  1.735707e-10    m
Sz                  3.429311e-10    m
Sdq                 2.783924e-03     
Sdr                 3.875098e-04    %
Sal                 3.608897e-08    m
Str                 2.364388e-01     
Std                 1.795000e+02    °
Correlation length  8.515676e-08    m

Height distribution¶

hist returns a normal matplotlib figure, so anything can be added to it, here a box with the main parameters.

In [4]:
Sa, Sq, Ssk, Sku = table.loc[["Sa", "Sq", "Ssk", "Sku"], "value"]

text = "\n".join((f"RMS (Sq): {Sq * 1e12:.1f} pm", f"Mean (Sa): {Sa * 1e12:.1f} pm",
                  f"Skew (Ssk): {Ssk:.3f}", f"Kurtosis (Sku): {Sku:.3f}"))
print(text)

fig = afm.hist(bins=256, figsize=(6, 4))
fig.axes[0].text(0.025, 0.95, text, va="top", transform=fig.axes[0].transAxes, fontsize=8,
                 bbox=dict(boxstyle="round", facecolor="w", alpha=0.5))
plt.show()
RMS (Sq): 42.1 pm
Mean (Sa): 33.6 pm
Skew (Ssk): -0.056
Kurtosis (Sku): 3.010
No description has been provided for this image

Bearing curve and power spectrum¶

The bearing curve shows how much of the surface lies above each height. The power spectral density shows at which lengths the roughness sits.

In [5]:
fig, axes = plt.subplots(1, 2, figsize=(11, 4), layout="constrained", dpi=150)
afm.plot_bearing(ax=axes[0], title="Bearing curve")
afm.plot_psd(ax=axes[1], title="Power spectral density")
plt.show()
No description has been provided for this image

Roughness along a line¶

A line cut, averaged over 5 pixels across the line, with its roughness after ISO 21920. End points are in m, as on the axes of the image.

In [6]:
width, height = afm.size()
profile = afm.line_profile((0.1 * width, 0.5 * height), (0.9 * width, 0.5 * height), width=5)

fig, axes = plt.subplots(1, 2, figsize=(11, 4), layout="constrained", dpi=150)
afm.image(ax=axes[0], profile=profile, color_range="p1")
afm.plot_profile(profile, ax=axes[1], title="Line cut")
plt.show()

roughness = afm.profile_roughness(profile).params
for name in ("Ra", "Rq", "Rz"):
    print(f"{name}: {roughness[name][0] * 1e12:.1f} pm")
No description has been provided for this image
Ra: 13.6 pm
Rq: 16.1 pm
Rz: 54.8 pm