Skip to content

Noise Interpolation

This script calculates the noise values throughout a building from a noise source. It takes as inputs a low_res and high_res version of the building, as well as a noise path, which consists of points. As an output it generates a quietness lattice.

0. Initialization

0.1. Load required libraries

import os
import topogenesis as tg
import pyvista as pv
import trimesh as tm
import numpy as np
import scipy as sp
from ladybug.sunpath import Sunpath
from scipy.interpolate import RegularGridInterpolator

0.2. Load the envelope lattice as the avialbility lattice

# loading the lattice from csv
lattice_path = os.path.relpath('../data/voxelized_envelope_lowres.csv')
avail_lattice = tg.lattice_from_csv(lattice_path)
init_avail_lattice = tg.to_lattice(np.copy(avail_lattice), avail_lattice)

0.3. Load noise sources

# loading noise points from CSV
noise_source_path = os.path.relpath('../data/noise_points_2.csv')
noise_sources = np.genfromtxt(noise_source_path, delimiter=',')
noise_sources

0.4. Visualize noise source points

# initiating the plotter
p = pv.Plotter(notebook=True)

# adding the avilability lattice
init_avail_lattice.fast_vis(p)

# adding axes
p.add_axes()

p.add_mesh(noise_sources, point_size=10)

p.show(use_ipyvtk=True)

1. Import Lattice (envelope)

1.1. Load the Envelope Lattice

# loading the lowres lattice from csv
lattice_path = os.path.relpath('../data/voxelized_envelope_lowres.csv')
envelope_lattice = tg.lattice_from_csv(lattice_path)


# loading the highres lattice from csv
lattice_path = os.path.relpath('../data/voxelized_envelope_highres.csv')
avail_lattice_highres = tg.lattice_from_csv(lattice_path)

2. Creation of Noise Field

2.1. Computing noise lattices

# create full lattice
full_lattice = envelope_lattice * 0 + 1

# extract the coordiantes of the centroid of all voxel
vox_centroids = full_lattice.centroids

# extract voxel indices of all voxels
vox_indices = np.array(np.where(full_lattice==1)).T

# setting the noise base pressure level 
noise_base = 75.0

# initializing the sum lattice of noise
sum_noise_lats = envelope_lattice * 0.0

# for each source of noise
for noise_src in noise_sources:
    # initialize the occupation lattice
    dist_latice = envelope_lattice * 0.0

    for cen, ind in zip(vox_centroids, vox_indices):
        # compute the euclidian distance
        dist_latice[tuple(ind)] = sp.spatial.distance.euclidean(cen, noise_src)

    # computing the noise lattice from dist lattice
    noise_latice = noise_base - 20 * np.log10(dist_latice) - 8

    # summing
    sum_noise_lats += np.power(10, noise_latice / 10.0)

# computing the final aggregation
agg_noise_lats = 10 * np.log10(sum_noise_lats)
2.2. Store noise access information in a Lattice
# initiating the plotter
p = pv.Plotter(notebook=True)

vis_lattice = agg_noise_lats

# Create the spatial reference
grid = pv.UniformGrid()

# Set the grid dimensions: shape because we want to inject our values
grid.dimensions = vis_lattice.shape
# The bottom left corner of the data set
grid.origin = vis_lattice.minbound
# These are the cell sizes along each axis
grid.spacing = vis_lattice.unit

# Add the data values to the cell data
grid.point_arrays["Noise"] = vis_lattice.flatten(order="F")  # Flatten the Lattice


# adding the volume
opacity = np.array([0,0.6,0.6,0.6,0.6,0.6,0.6])*1.5
p.add_volume(grid, cmap="coolwarm" ,opacity=opacity, shade=True)

# plotting
p.show(use_ipyvtk=True)
#Convert the noise distaqnces to a ratio
agg_noise_ratio_lats = 1 -  ( agg_noise_lats - np.min(agg_noise_lats)) / (np.max(agg_noise_lats) - np.min(agg_noise_lats))

3. Interpolation

def interpolate(info_lowres, base_highres):
    # line spaces
    x_space = np.linspace(info_lowres.minbound[0], info_lowres.maxbound[0],info_lowres.shape[0])
    y_space = np.linspace(info_lowres.minbound[1], info_lowres.maxbound[1],info_lowres.shape[1])
    z_space = np.linspace(info_lowres.minbound[2], info_lowres.maxbound[2],info_lowres.shape[2])

    # interpolation function
    interpolating_function = RegularGridInterpolator((x_space, y_space, z_space), info_lowres, bounds_error=False, fill_value=None)

    # high_res lattice
    envelope_lattice = base_highres + 1

    # sample points
    sample_points = envelope_lattice.centroids

    # interpolation
    interpolated_values = interpolating_function(sample_points)

    # lattice construction
    info_highres = tg.to_lattice(interpolated_values.reshape(base_highres.shape), base_highres)

    # nulling the unavailable cells
    info_highres *= base_highres

    return info_highres
noise_highres = interpolate(agg_noise_ratio_lats, avail_lattice_highres)
# load the context and the envelope
envelope_path = os.path.relpath("../data/compulsory_envelope.obj")
context_path = os.path.relpath("../data/immediate_context.obj")

# load the mesh from file
envelope_mesh = tm.load(envelope_path)
context_mesh = tm.load(context_path)

# Check if the mesh is watertight
print(envelope_mesh.is_watertight)
print(context_mesh.is_watertight)

3.1. Visualize the interpolated noise

# initiating the plotter
p = pv.Plotter(notebook=True)

vis_lattice = noise_highres
# Create the spatial reference
grid = pv.UniformGrid()

# Set the grid dimensions: shape because we want to inject our values
grid.dimensions = vis_lattice.shape
# The bottom left corner of the data set
grid.origin = vis_lattice.minbound
# These are the cell sizes along each axis
grid.spacing = vis_lattice.unit

# Add the data values to the cell data
grid.point_arrays["Noise Highress"] = vis_lattice.flatten(order="F")  # Flatten the Lattice


# # adding the meshes
p.add_mesh(tri_to_pv(context_mesh), opacity=0.1, style='wireframe')

# adding the volume
opacity = np.array([0,0.6,0.6,0.6,0.6,0.6,0.6])*1.5
p.add_volume(grid, cmap="plasma", clim=[0.0, 1],opacity=opacity, shade=True)

# plotting
p.show(use_ipyvtk=True)

png_path = os.path.relpath('../screen/quietness.png')
p.show(screenshot = png_path)

4. Save Quietness Access Lattice into a CSV

#select a path and a name to save the csv
csv_path = os.path.relpath('../data/quietness_highres.csv')
noise_highres.to_csv(csv_path)

Credits

__author__ = "Shervin Azadi"
__editor__ = 'Siebren Meines'
__license__ = "MIT"
__version__ = "1.0"
__url__ = "https://github.com/shervinazadi/spatial_computing_workshops"
__summary__ = "Noise interpolation calculation"