Skip to content

Commit

Permalink
Documentation (#29)
Browse files Browse the repository at this point in the history
* Added class and function docstrings

* Updated docstrings and README

* Linting and fixed tests

* Added docs and README

* Linting
  • Loading branch information
marc1701 authored Dec 1, 2023
1 parent f005cfa commit bd5f2bc
Show file tree
Hide file tree
Showing 16 changed files with 4,650 additions and 83 deletions.
74 changes: 73 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,74 @@
# uas-sound-event
Render movement events from static hover UAS source recordings
Simulates simple atmospheric acoustic
propagation effects for rendering multichannel auralisations of
unmanned aerial systems (UAS - drones), or other airborne sources,
in motion.

The model assumes that input source signals have been recorded at a fixed
distance and with a fixed rotational speed. Auralisations are created
assuming free-field propagation and account for the following:
* Doppler effect
* Distance-dependent atmospheric absorption of high frequencies
* Ground reflection (including path length difference and
angle-dependent high-frequency absorption)
* Distance-based amplitude panning (DBAP) to spatialise source in 3D
loudspeaker array (direct sound and ground reflection spatialised
separately).

**Author**: Marc C. Green ([email protected])

**Affiliation**: University of Salford (Acoustics Research Centre)

**Copyright statement**: This file and code is part of work undertaken within
the REFMAP project (www.refmap.eu), and is subject to license.

Based on method detailed in: [_Heutschi, K., Ott, B., Nussbaumer, T., and Wellig, P.,
"Synthesis of real world drone signals based on lab recordings,"
Acta Acustica, Vol. 4, No. 6, 2020, p. 24._](https://doi.org/10.1051/aacus/2020023)

## Usage
The main object implementing the propagation model is `UASEventRenderer`. This
object is initialised using CSV files defining flightpaths in segments. Each
segment requires the definition of start and end points in cartesian
co-ordinates, along with starting and ending speeds in meters per second.
The following is an example flightpath configuration file with four segments.
Further examples can be found in the `flights/` directory.

```
segment, startxyz, endxyz, speeds
constant-speed flyby, 10 -200 30, 10 180 30, 30 30
decelerate, 10 180 30, 10 200 30, 30 0
accelerate, 10 200 30, 10 180 30, 0 30
flyby back, 10 180 30, 10 -200 30, 30 30
```

Using these CSV flightpath definitions, `UASEventRenderer` calculates the
position of the source at every sample time. These positions are used to
calculate the delays, distances, and angles required to render the propagation
effects based on a listener located at the origin of the co-ordinate system.

The listener height is set to 1.5 m by default. This affects the calculation
of the ground reflection signal in particular. Additional parameters include
the ground material, which can be selected from `'grass'`, `'soil'`, or
`'asphalt'`, and the loudspeaker layout to target with the DBAP panning
(currently only `'Octagon + Cube'` is implemented).

The object's `render()` method can then be used to generate a time-series
signal at the receiver point. The input source used should be sufficient in
length to cover the time taken to cover the entire defined flightpath.

The following is a basic script for rendering an event:

```
import soundfile as sf
from uasevent.environment import UASEventRenderer
from uasevent.utils import load_params
x, fs = sf.read('example_source.wav')
renderer = UASEventRenderer(
load_params('flightpath.csv'),
receiver_height=1.5,
fs=fs)
output = renderer.render(x)
```
7 changes: 7 additions & 0 deletions docs/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="refresh" content="0; url=./uasevent.html"/>
</head>
</html>
46 changes: 46 additions & 0 deletions docs/search.js

Large diffs are not rendered by default.

406 changes: 406 additions & 0 deletions docs/uasevent.html

Large diffs are not rendered by default.

2,134 changes: 2,134 additions & 0 deletions docs/uasevent/environment.html

Large diffs are not rendered by default.

746 changes: 746 additions & 0 deletions docs/uasevent/interpolators.html

Large diffs are not rendered by default.

769 changes: 769 additions & 0 deletions docs/uasevent/utils.html

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion flights/demo_flight_flyby_X.csv
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
segment, startxyz, endxyz, speeds
constant-speed flyby, -200 0 30, 200 0 30, 30 30
constant-speed flyby, -200 0 10, 200 0 10, 15 15
2 changes: 1 addition & 1 deletion flights/demo_flight_flyby_Y.csv
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
segment, startxyz, endxyz, speeds
constant-speed flyby, 0 -200 30, 0 200 30, 30 30
constant-speed flyby, 0 -200 10, 0 200 10, 15 15
107 changes: 106 additions & 1 deletion poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ flake8 = "^6.1.0"
seaborn = "^0.13.0"
coverage = "^7.3.2"
pyloudnorm = "^0.1.1"
pdoc = "^14.1.0"

[build-system]
requires = ["poetry-core"]
Expand Down
14 changes: 7 additions & 7 deletions tests/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import soundfile as sf
import uasevent.utils as utils
import uasevent.interpolators as interpolators
from uasevent.environment_model import UASEventRenderer
from uasevent.environment import UASEventRenderer
from numpy.testing import assert_array_almost_equal


Expand Down Expand Up @@ -102,7 +102,7 @@ def __init__(self, methodName: str = "runTest") -> None:
params = utils.load_params('tests/test_flight.csv')
self.renderer = UASEventRenderer(params, 'asphalt', fs, 1.5)
self.xout = self.renderer.render(self.x)
self.dir_x = self.renderer.d
self.dir_x = self.renderer._d

params_2 = utils.load_params('tests/test_flight_2.csv')
self.renderer_2 = UASEventRenderer(params_2, 'asphalt', fs, 1.5)
Expand All @@ -112,15 +112,15 @@ def test_output_sensible(self):
self.assertEqual(len(self.renderer._flightpath.T), len(self.xout))

# direct path should have higher power than reflection
self.assertGreater(np.sum(abs(self.renderer.d)),
np.sum(abs(self.renderer.r)))
self.assertGreater(np.sum(abs(self.renderer._d)),
np.sum(abs(self.renderer._r)))

# first n samples of reflected signal should be zero
n = int(np.floor(
self.renderer.ground_reflection.init_delay
- self.renderer.direct_path.init_delay
self.renderer.ground_reflection._init_delay
- self.renderer.direct_path._init_delay
))
self.assertTrue((self.renderer.r[:n] == 0).all())
self.assertTrue((self.renderer._r[:n] == 0).all())

# rendering of greater distance should have larger scaling
self.assertGreater(1/self.renderer_2._norm_scaling,
Expand Down
Loading

0 comments on commit bd5f2bc

Please sign in to comment.