Chapter 4 Geotechnical Engineering: Particle size distribution#
1. Introduction#

Fig. 15 **Figure 4.1 **: Particle Size Distribution.#
🧱 Particle Size and Distribution in Geotechnical Properties#
Particle Size Distribution (PSD) refers to the proportion of different grain sizes present in a soil sample. It is typically determined through:
Sieve analysis for coarse-grained soils (sand, gravel)
Hydrometer analysis for fine-grained soils (silt, clay): Based on sedimentation and Stokes’ Law; - Suitable for fine-grained soils (silt and clay)- Measures settling velocity in a fluid column
The results are plotted as a gradation curve, showing the percentage of material finer than a given size.
🔬 Alternative Methods for Particle Size Distribution (PSD)#
Beyond traditional sieve analysis, several advanced techniques are used to characterize particle size across a wide range of materials and scales:
Laser Diffraction (LD)
Uses light scattering to estimate particle size - Covers ~0.01 µm to 2000 µm range - Assumes spherical particles; rapid and automated
Dynamic Light Scattering (DLS)
Measures Brownian motion of particles in suspension - Ideal for nanoparticles (0.3 nm to ~10 µm) - Provides hydrodynamic diameter
Dynamic Image Analysis (DIA)
Captures real-time images of particles in motion - Measures both size and shape - Useful for multimodal and irregular distributions
Scanning Electron Microscopy (SEM)
Direct imaging of particle morphology and size - Suitable for particles >10 nm - Offers detailed surface texture analysis
Coulter Counter (Electrical Sensing Zone Method)
Detects changes in electrical resistance as particles pass through an orifice - Effective for sizing and counting particles in suspension
These methods vary in resolution, cost, and assumptions about particle shape, making them complementary tools depending on the material and engineering context.
📐 Key Parameters from PSD#
Parameter |
Description |
---|---|
D10 |
Diameter at which 10% of soil is finer (effective size) |
D30, D60 |
Diameters at 30% and 60% finer; used in uniformity and gradation calculations |
Cu (Uniformity Coefficient) |
( Cu = \frac{D60}{D10} ); indicates soil gradation |
Cc (Coefficient of Curvature) |
( Cc = \frac{D30^2}{D10 \cdot D60} ); indicates shape of curve |
🧠 Why Particle Size Distribution Is Important#
1. Classification#
Determines whether soil is coarse-grained (sand, gravel) or fine-grained (silt, clay)
Used in systems like USCS and AASHTO
2. Permeability#
Well-graded soils (wide range of sizes) have lower permeability
Uniform soils (similar sizes) allow faster drainage
3. Compaction and Density#
PSD affects maximum dry density and optimum moisture content
Well-graded soils compact better and achieve higher strength
4. Shear Strength#
Coarse particles provide frictional resistance
Fines influence cohesion and plasticity
5. Frost Susceptibility#
Fine soils (especially silts) are more prone to frost heave
6. Filter Design and Drainage#
PSD ensures proper filter compatibility to prevent piping and clogging
📊 Role of Particle Size in Geotechnical Properties#
Property |
Influence of Particle Size |
---|---|
Strength |
Larger particles increase friction; fines add cohesion |
Compressibility |
Fine soils compress more under load |
Permeability |
Coarse soils drain faster; fines retain water |
Plasticity |
Controlled by clay content and mineralogy |
Stability |
Well-graded soils resist erosion and settlement |
🧠 Conceptual Insight#
Particle size distribution is the foundation of soil classification and behavior prediction —
it governs how soil responds to loading, drainage, compaction, and environmental changes.
References#
[Das, 2010] provides a clear and pedagogically rich explanation of particle size distribution (PSD). Furthermore, the three ASTM standards for particle size distribution (PSD) testing provide complementary methods for analyzing soil gradation. ASTM D422 [ASTM International, 1963], now withdrawn, historically combined sieve and hydrometer techniques to assess both coarse and fine fractions in a single procedure. It has since been replaced by two more specialized standards: ASTM D6913 [ASTM International, 2004], which covers sieve analysis for coarse-grained soils such as sand and gravel, and ASTM D7928 {cite: p}ASTM_D7928
, which details hydrometer analysis for fine-grained soils like silt and clay. D6913 outlines procedures for dry sieving, including calculations for the coefficient of uniformity and curvature, while D7928 applies sedimentation principles based on Stokes’ Law, incorporating corrections for temperature and dispersant effects. Together, D6913 and D7928 form the current ASTM framework for accurately characterizing soil gradation across the full particle size spectrum.
2. Simulation#
Interactive Particle Size Distribution (PSD) Tool#
This notebook provides an interactive tool for analyzing Particle Size Distribution (PSD) in soil mechanics. It is designed for educational use and includes:
This tool:
Computes key PSD parameters: D10, D30, D60
Calculates Uniformity Coefficient (Cu) and Curvature Coefficient (Cc)
Classifies soil gradation (e.g., GW, SW, GP, SP) based on empirical criteria
Visualizes the gradation curve using Plotly
Interprets soil type based on fines content and PSD shape
🔧 Computational Steps#
User Inputs:
Sieve Sizes (mm)
: Grain diameters used in sieve analysisPercent Passing (%)
: Cumulative percentage of soil passing each sieve
Calculations:
Interpolates D10, D30, D60 from the gradation curve
Computes: \( Cu = \frac{D60}{D10}, \quad Cc = \frac{D30^2}{D10 \cdot D60} \)
Determines fines content (percent passing 0.075 mm)
Applies classification rules based on Cu, Cc, and fines
Visualization:
Plots PSD curve with D-values highlighted
Uses log scale and reversed axes for standard soil gradation format
📊 How to Interpret Inputs#
Input Field |
Meaning |
---|---|
|
Grain sizes used in sieve analysis |
|
Cumulative percent of soil finer than each sieve size |
📋 How to Interpret Outputs#
Output Parameter |
Interpretation |
---|---|
|
Key grain sizes used in classification and permeability estimation |
|
Indicates soil gradation; Cu ≥ 4 (gravel), Cu ≥ 6 (sand) = well-graded |
|
Indicates curve shape; 1 ≤ Cc ≤ 3 = well-graded |
|
Helps distinguish coarse vs. fine-grained soils |
|
Soil type based on gradation and fines (e.g., GW, SW, SP, SC, SM) |
|
Visual representation of soil gradation |
🧠 Conceptual Insight#
This tool links grain size distribution to soil classification and engineering behavior —
helping geotechnical engineers assess drainage, compaction, and stability characteristics.
import numpy as np
import plotly.graph_objects as go
import ipywidgets as widgets
from IPython.display import display, Markdown
def compute_d_values(sieve_sizes, percent_passing):
D10 = np.interp(10, percent_passing[::-1], sieve_sizes[::-1])
D30 = np.interp(30, percent_passing[::-1], sieve_sizes[::-1])
D60 = np.interp(60, percent_passing[::-1], sieve_sizes[::-1])
return D10, D30, D60
def plot_psd(sieve_sizes, percent_passing, D10, D30, D60):
fig = go.Figure()
fig.add_trace(go.Scatter(x=sieve_sizes, y=percent_passing, mode='lines+markers', name='PSD Curve'))
fig.add_trace(go.Scatter(x=[D10], y=[10], mode='markers+text', name='D10',
text=["D10"], textposition="top center", marker=dict(size=10, color='red')))
fig.add_trace(go.Scatter(x=[D30], y=[30], mode='markers+text', name='D30',
text=["D30"], textposition="top center", marker=dict(size=10, color='green')))
fig.add_trace(go.Scatter(x=[D60], y=[60], mode='markers+text', name='D60',
text=["D60"], textposition="top center", marker=dict(size=10, color='blue')))
fig.update_layout(title='Particle Size Distribution Curve',
xaxis_title='Sieve Size (mm)',
yaxis_title='Percent Passing (%)',
xaxis_type='log',
xaxis=dict(autorange='reversed'),
yaxis=dict(autorange='reversed'),
width=800, height=500)
fig.show()
def classify_soil_by_gradation(Cu, Cc):
if Cu >= 4 and 1 <= Cc <= 3:
return "Well-graded gravel (GW)"
elif Cu >= 6 and 1 <= Cc <= 3:
return "Well-graded sand (SW)"
else:
return "Poorly graded soil (GP/SP)"
sieve_input = widgets.Text(
value='4.75, 2.0, 1.0, 0.425, 0.25, 0.075',
description='Sieve Sizes (mm):',
layout=widgets.Layout(width='100%'),
style={'description_width': 'initial'}
)
passing_input = widgets.Text(
value='100, 90, 70, 50, 30, 10',
description='Percent Passing (%):',
layout=widgets.Layout(width='100%'),
style={'description_width': 'initial'}
)
output = widgets.Output()
def update_plot(change=None):
output.clear_output()
with output:
try:
sieve_sizes = np.array([float(x.strip()) for x in sieve_input.value.split(',')])
percent_passing = np.array([float(x.strip()) for x in passing_input.value.split(',')])
if len(sieve_sizes) != len(percent_passing):
display(Markdown("❌ **Error:** Number of sieve sizes and percent passing values must match."))
return
sorted_indices = np.argsort(sieve_sizes)[::-1]
sieve_sizes = sieve_sizes[sorted_indices]
percent_passing = percent_passing[sorted_indices]
D10, D30, D60 = compute_d_values(sieve_sizes, percent_passing)
Cu = D60 / D10 if D10 != 0 else np.nan
Cc = (D30**2) / (D10 * D60) if D10 != 0 and D60 != 0 else np.nan
classification = classify_soil_by_gradation(Cu, Cc)
display(Markdown(f"### 📐 Calculated Parameters"))
display(Markdown(f"- **D10:** {D10:.3f} mm - **D30:** {D30:.3f} mm - **D60:** {D60:.3f} mm"))
display(Markdown(f"- **Coefficient of Uniformity (Cu):** {Cu:.2f} - **Coefficient of Curvature (Cc):** {Cc:.2f}"))
display(Markdown(f"### 🧠 Soil Gradation Hint: **{classification}**"))
plot_psd(sieve_sizes, percent_passing, D10, D30, D60)
except Exception as e:
display(Markdown(f"❌ **Error:** {e}"))
sieve_input.observe(update_plot, names='value')
passing_input.observe(update_plot, names='value')
display(widgets.VBox([sieve_input, passing_input]), output)
update_plot()
import numpy as np
def classify_soil_from_psd(sieve_sizes, percent_passing):
sorted_indices = np.argsort(sieve_sizes)[::-1]
sieve_sizes = np.array(sieve_sizes)[sorted_indices]
percent_passing = np.array(percent_passing)[sorted_indices]
D10 = np.interp(10, percent_passing[::-1], sieve_sizes[::-1])
D30 = np.interp(30, percent_passing[::-1], sieve_sizes[::-1])
D60 = np.interp(60, percent_passing[::-1], sieve_sizes[::-1])
Cu = D60 / D10 if D10 != 0 else np.nan
Cc = (D30 ** 2) / (D10 * D60) if D10 != 0 and D60 != 0 else np.nan
fines_index = np.where(np.array(sieve_sizes) <= 0.075)[0]
percent_fines = percent_passing[fines_index[0]] if fines_index.size > 0 else 0
if percent_fines > 50:
classification = "Fine-grained soil (Use Atterberg limits for further classification)"
elif percent_fines > 12:
classification = "Coarse-grained soil with fines (e.g., SC, SM, GC, GM)"
else:
if D10 == 0 or D60 == 0:
classification = "Insufficient data for classification"
elif Cu >= 4 and 1 <= Cc <= 3:
classification = "Well-graded gravel (GW)" if sieve_sizes[0] > 4.75 else "Well-graded sand (SW)"
else:
classification = "Poorly graded gravel (GP)" if sieve_sizes[0] > 4.75 else "Poorly graded sand (SP)"
return {
'D10 (mm)': round(D10, 3),
'D30 (mm)': round(D30, 3),
'D60 (mm)': round(D60, 3),
'Cu': round(Cu, 2),
'Cc': round(Cc, 2),
'Percent Fines': round(percent_fines, 1),
'Classification': classification
}
# Example dataset
sieve_sizes = [4.75, 2.0, 1.0, 0.425, 0.25, 0.075]
percent_passing = [100, 90, 70, 50, 30, 10]
# Run classification
result = classify_soil_from_psd(sieve_sizes, percent_passing)
# Display results
for key, value in result.items():
print(f"{key}: {value}")
D10 (mm): 0.075
D30 (mm): 0.25
D60 (mm): 0.712
Cu: 9.5
Cc: 1.17
Percent Fines: 10
Classification: Well-graded sand (SW)
3. Self-Assessment#
Reflective Questions#
How does particle size distribution affect the properties of materials in different industries?
What are the advantages and limitations of different particle size measurement techniques?
How can understanding particle size distribution improve product quality and performance?
What challenges might arise when interpreting particle size distribution data?
Conceptual Questions#
Define particle size distribution and explain its significance in material science.
Describe the process of laser diffraction and how it is used to measure particle size.
Explain the importance of D10, D30, and D60 values in particle size distribution analysis.
What is the difference between well-graded and poorly graded soils? How are these classifications determined?
Quiz#
import numpy as np
import ipywidgets as widgets
from IPython.display import display, Markdown
# Quiz Questions
questions = [
{
"question": "What does D10 represent in particle size distribution?",
"options": ["The diameter at which 10% of the sample's mass is finer", "The diameter at which 10% of the sample's mass is coarser", "The average particle size", "The largest particle size"],
"answer": "The diameter at which 10% of the sample's mass is finer"
},
{
"question": "Which technique uses laser light scattering to measure particle size?",
"options": ["Dynamic Light Scattering", "Laser Diffraction", "Image Analysis", "Centrifugal Sedimentation"],
"answer": "Laser Diffraction"
},
{
"question": "What is the Coefficient of Uniformity (Cu) used for?",
"options": ["To determine the average particle size", "To classify the soil gradation", "To measure the particle shape", "To calculate the particle density"],
"answer": "To classify the soil gradation"
},
{
"question": "What does a high percentage of fines indicate about the soil?",
"options": ["The soil is well-graded", "The soil is poorly graded", "The soil is fine-grained", "The soil is coarse-grained"],
"answer": "The soil is fine-grained"
}
]
# Function to create quiz
def create_quiz(questions):
quiz_widgets = []
for q in questions:
question_widget = widgets.VBox([
widgets.HTML(value=f"<b>{q['question']}</b>"),
widgets.RadioButtons(options=q['options'], layout={'width': 'max-content'})
])
quiz_widgets.append(question_widget)
return quiz_widgets
# Function to check answers
def check_answers(quiz_widgets, questions):
score = 0
for i, widget in enumerate(quiz_widgets):
selected = widget.children[1].value
if selected == questions[i]['answer']:
score += 1
return score
# Display quiz
quiz_widgets = create_quiz(questions)
display(widgets.VBox(quiz_widgets))
# Button to submit answers
submit_button = widgets.Button(description="Submit Answers")
output = widgets.Output()
def on_submit(b):
with output:
output.clear_output()
score = check_answers(quiz_widgets, questions)
display(Markdown(f"### Your Score: {score}/{len(questions)}"))
submit_button.on_click(on_submit)
display(submit_button, output)