| 2181 | self.simulator_state["ism_done"] = True |
| 2182 | |
| 2183 | def ray_tracing(self): |
| 2184 | if not self.simulator_state["rt_needed"]: |
| 2185 | return |
| 2186 | |
| 2187 | n_rays = self.rt_args["n_rays"] |
| 2188 | n_dirs = self.rt_args["receiver_n_directions"] |
| 2189 | n_bands = len(self.octave_bands.get_bw()) if self.is_multi_band else 1 |
| 2190 | |
| 2191 | # Check if all sources/receivers are omnidirectional. |
| 2192 | mic_all_omni = all([d is None for d in self.mic_array.directivity]) |
| 2193 | src_all_omni = all([s.directivity is None for s in self.sources]) |
| 2194 | is_all_omni = mic_all_omni and src_all_omni |
| 2195 | |
| 2196 | # For directive sources, we need to define directions. |
| 2197 | default_source_directions = fibonacci_spherical_sampling(n_rays).T |
| 2198 | default_source_energies = np.ones((n_rays, n_bands)) |
| 2199 | |
| 2200 | # For directive microphones, we need to enable direction sensitive receivers. |
| 2201 | default_directions = fibonacci_spherical_sampling(n_dirs).T |
| 2202 | self.rt_directional_responses = [] |
| 2203 | for r, directivity in enumerate(self.mic_array.directivity): |
| 2204 | if directivity is None: |
| 2205 | # When no directivity is provided, the microphones are omnidirectional. |
| 2206 | self.room_engine.microphones[r].make_omnidirectional() |
| 2207 | self.rt_directional_responses.append( |
| 2208 | { |
| 2209 | "response": np.ones(1), |
| 2210 | "is_impulse_response": False, |
| 2211 | } |
| 2212 | ) |
| 2213 | else: |
| 2214 | if isinstance(directivity, MeasuredDirectivity): |
| 2215 | # Measured directivities already have a direction grid |
| 2216 | # that we can reuse. |
| 2217 | dir_vectors = directivity.get_direction_vectors() |
| 2218 | else: |
| 2219 | # Otherwise, we use the default directions. |
| 2220 | dir_vectors = default_directions |
| 2221 | self.room_engine.microphones[r].set_directions(dir_vectors) |
| 2222 | self.rt_directional_responses.append( |
| 2223 | { |
| 2224 | "response": directivity.get_response_cartesian(dir_vectors), |
| 2225 | "is_impulse_response": directivity.is_impulse_response, |
| 2226 | } |
| 2227 | ) |
| 2228 | |
| 2229 | # this will be a list of lists with |
| 2230 | # shape (n_mics, n_src, n_directions, n_bands, n_time_bins) |
| 2231 | self.rt_histograms = [[] for r in range(self.mic_array.M)] |
| 2232 | |
| 2233 | for s, src in enumerate(self.sources): |
| 2234 | # Create the directivity pattern if needed. |
| 2235 | if src.directivity is None: |
| 2236 | source_directions = default_source_directions |
| 2237 | source_energies = default_source_energies |
| 2238 | else: |
| 2239 | source_directions, source_energies = src.directivity.sample_rays(n_rays) |
| 2240 | source_energies = np.broadcast_to(source_energies, (n_rays, n_bands)) |