|
| 1 | + |
1 | 2 | # pytARD
|
2 |
| -(Python-) based ARD reverberation experimentation repository |
| 3 | +**pytARD** is a free and open source Python room impulse response generator using Adaptive Rectangular Decomposition (ARD) for auralization and visualization of wave distribution and reverberation inside rooms. |
| 4 | + |
| 5 | + |
| 6 | +## Prerequisites |
| 7 | + - **OS:** Developed and tested on GNU/Linux systems (Ubuntu 20.04 LTS), macOS (10.14 and 11.6) and Windows 10 |
| 8 | + - **Python:** Python 3 required. Developed and tested on version 3.8.2 and 3.9.2. Older as well as newer versions should run with no problems. |
| 9 | +- **Required Python packages**: For core functionality, matplotlib 3.3.4, numpy 1.20.1, scipy 1.6.2 and 4.64.0 needs to be installed. |
| 10 | +## Installation |
| 11 | +You can use `git pull` to pull this repository on your hard drive, alternative download this repository as a .zip file. |
| 12 | +## License |
| 13 | +This software is subject to the [GNocchi Alfredo AGPL-3.0 license](https://www.gnu.org/licenses/agpl-3.0.en.html). This software comes with no warranty. |
| 14 | +## Acknowledgements |
| 15 | +If you find this software helpful, feel free to cite us. |
| 16 | + |
| 17 | +> [1] Corrodi, O., Fürbringer & S., Smailov, N. pytARD: A free and open |
| 18 | +> source Python room impulse response generator using Adaptive |
| 19 | +> Rectangular Decomposition (ARD). |
| 20 | +
|
| 21 | + @thesis{pytard2022, |
| 22 | + author = {Fürbringer, Severin and Corrodi, Oliver and Smailov, Nikita}, |
| 23 | + title = {GPU-based Time Domain Solver for Acoustic Wave Equation}, |
| 24 | + school = {ZHAW School of Engineering}, |
| 25 | + year = {2022}, |
| 26 | + month = {July}, |
| 27 | + type = {Bachelor's Thesis} |
| 28 | + } |
| 29 | +# Documentation |
| 30 | +pytARD comes with three different implementation to simulate 1D, 2D and 3D spaces. |
| 31 | +## SimulationParameters |
| 32 | +Data container for defining simulation parameters. |
| 33 | +``` |
| 34 | +sim_param = SimulationParameters( |
| 35 | + max_simulation_frequency=250, # Highest frequency |
| 36 | + T=1, # Simulation duration |
| 37 | + spatial_samples_per_wave_length=6 # Discrete points per single wave length |
| 38 | + c=343, # Speed of sound |
| 39 | + Fs=8000, # Sample rate |
| 40 | + verbose=True # Console output |
| 41 | + visualize=True # Visualization of wave distribution |
| 42 | +) |
| 43 | +``` |
| 44 | +## Impulses |
| 45 | +Impulses can be used as source signal, which is passed off into a certain partition. |
| 46 | +### Common parameters |
| 47 | +Following parameters are shared between all types of impulse. |
| 48 | + - `amplitude`: How loud the impulse is. |
| 49 | + - `impulse_location`: Position of the impulse. Numpy array with coordinates according to which dimensional implementation of pytARD was used, for example `impulse_location = np.array([[2], [2], [2])` for 3D. |
| 50 | + |
| 51 | +### Impulse types |
| 52 | +There are three different types of impulses in pytARD. |
| 53 | + - **Unit impulse:** This is the standard impulse in RIR generators. `impulse = Unit(sim_param, impulse_location, amplitude)` |
| 54 | + - **Gaussian impulse:** `impulse = Gaussian(sim_param, impulse_location, amplitude)` |
| 55 | + - **Wave file:** `impulse = WaveFile(sim_param, impulse_location, 'path_to_file.wav', amplitude)` |
| 56 | + |
| 57 | +## Partitions |
| 58 | +Partitions make up parts of the domain (the room to be simulated). Those partitions can be connected via interfaces to allow travel of sound waves from partition to partition. |
| 59 | +### Air Partitions |
| 60 | +An air partition resembles an empty space in which sound can travel through. Air partitions reflect acoustic waves indefinitely without loss in amplitude. |
| 61 | +#### 1D example |
| 62 | +``` |
| 63 | +room_width = 5 |
| 64 | +partition = AirPartition1D(room_width, sim_param, impulse) |
| 65 | +``` |
| 66 | +#### 2D example |
| 67 | +``` |
| 68 | +air_partition = AirPartition2D( |
| 69 | + np.array([[4.0], [4.0]]), # Room width and height |
| 70 | + sim_param, # SimulationParameters object |
| 71 | + impulse=impulse) # Impulse object |
| 72 | +) |
| 73 | +``` |
| 74 | +#### 3D example |
| 75 | +``` |
| 76 | +air_partition = AirPartition3D(np.array([ |
| 77 | + [4], # X, width of partition |
| 78 | + [4], # Y, depth of partition |
| 79 | + [2] # Z, height of partition |
| 80 | + ]), |
| 81 | + sim_param, # SimulationParameters object |
| 82 | + impulse=impulse # Impulse object |
| 83 | +) |
| 84 | +``` |
| 85 | +### PML Partitions |
| 86 | +Perfectly Matched Layer (PML) partitions absorb sound energy depending on the damping profile and its reflection coefficient. |
| 87 | +``` |
| 88 | +pml_partition = PMLPartition2D( |
| 89 | + np.array([[1.0], [4.0]]), # Partition width and height |
| 90 | + sim_param, # SimulationParameters object |
| 91 | + dp) |
| 92 | +) |
| 93 | +``` |
| 94 | +#### Damping Profile |
| 95 | +Determines how intense the reflections of the PML partition are, or how much sound energy is absorbed. Be sure to pass the width of the partition as the first parameter. |
| 96 | +``` |
| 97 | +room_width = 4 |
| 98 | +reflection_coefficient = 1e-8 |
| 99 | +dp = DampingProfile(room_width, c, reflection_coefficient) |
| 100 | +``` |
| 101 | +## Interfaces |
| 102 | +Interfaces are used for connecting partitions with each other. Interfaces allow for the passing of sound waves between two partitions. To define interfaces, the helper class `Interface` is used. |
| 103 | +### Example |
| 104 | +It is required for all partitions to be collected in a `List` first. The indices of this list is referenced in the interface creation later. |
| 105 | +``` |
| 106 | +domain = [ |
| 107 | + air_partition_1, # Index 0 |
| 108 | + air_partition_2, # Index 1 |
| 109 | + ... # Index n |
| 110 | +] |
| 111 | +``` |
| 112 | +An interface is defined by referencing above mentioned List indices. To connect the first two air partition together, their `List` indices are passed as parameters. Since interfaces need a direction (or axis) to travel through, the third parameter is either `Direction.X`, `Direction.Y` or `Direction.Z` |
| 113 | +``` |
| 114 | +interface_1_0 = Interface(1, 0, Direction.X) |
| 115 | +``` |
| 116 | +## Microphone |
| 117 | +To auralize the simulation and create RIRs, virtual microphones are to be created and placed inside a partition within the domain. The `position` parameter needs to be adjusted to the according dimension and position. |
| 118 | + |
| 119 | +Just like [interfaces](##Interfaces), the microphones needs to be mapped to the according partition `List` indices. |
| 120 | +``` |
| 121 | +mic = Mic( |
| 122 | + 0, # Parition number (partition list index) |
| 123 | + [ # Positioning of microphone. |
| 124 | + 1, # X coordinate of partition |
| 125 | + 1, # Y coordinate of partition |
| 126 | + 1 # Z coordinate of partition |
| 127 | + ], |
| 128 | + sim_param, |
| 129 | + "RIR" # Name of resulting wave file |
| 130 | +) |
| 131 | +``` |
| 132 | +## ARDSimulator |
| 133 | +Room Impulse Responses (RIRs) simulation using the Adaptive Rectangular Decomposition (ARD). For further details see [\[1\]](#Acknowledgements). |
| 134 | +``` |
| 135 | +sim = ARDSimulator3D( # Can also be 2D and 1D |
| 136 | + sim_param, # SimulationParameters object |
| 137 | + partitions, # List of Partition objects |
| 138 | + interface_data=interfaces, # List of Interface objects |
| 139 | + mics=mics # List of Microphone objects |
| 140 | +) |
| 141 | +sim.preprocessing() # Start preprocessing |
| 142 | +sim.simulation() # Start the simulation |
| 143 | +``` |
| 144 | +## Plotter |
| 145 | +To visualize the wave distribution, a `Plotter` class is provided. |
| 146 | + |
| 147 | +To ensure correct display of each partition of the domain, the `plot_structure` variable needs to be adjusted according to following graph: |
| 148 | + |
| 149 | +To ensure correct representation of the setup above, `plot_structure` needs to be configured as following: |
| 150 | +``` |
| 151 | +plot_structure = [ |
| 152 | +# Structure: [Height of domain, width of domain, index of partition to plot on the graph] |
| 153 | + [2, 3, 1], |
| 154 | + [2, 3, 2], |
| 155 | + [2, 3, 3], |
| 156 | + [2, 3, 5] |
| 157 | +] |
| 158 | +``` |
| 159 | +To start plotting, use following instructions: |
| 160 | +``` |
| 161 | +plotter = Plotter() |
| 162 | +plotter.set_data_from_simulation(sim_param, partitions, mics, plot_structure) |
| 163 | +plotter.plot() |
| 164 | +``` |
| 165 | +## Serializer |
| 166 | +As the ARD method is resource heavy, a means to save simulation data to disk, as well as post-generation visualization and auralization is provided. Be sure to call serializer after the simulation was completed fully. **Necessary parameters** are `SimulationParameters` and a `List` of `Partition` objects, **optional parameters** are a `List` of `Microphone` objects for auralization and `plot_structure` for visualization. |
| 167 | +``` |
| 168 | +# Instantiation serializer for reading and writing simulation state data |
| 169 | +serializer = Serializer() |
| 170 | +serializer.dump(sim_param, partitions, mics, plot_structure) |
| 171 | +``` |
0 commit comments