Path: blob/main/latex-templates/templates/acoustics/room_acoustics.tex
51 views
unlisted
% Room Acoustics Analysis with PythonTeX1\documentclass[11pt,a4paper]{article}2\usepackage[utf8]{inputenc}3\usepackage[T1]{fontenc}4\usepackage{amsmath,amssymb}5\usepackage{graphicx}6\usepackage{booktabs}7\usepackage{siunitx}8\usepackage{geometry}9\geometry{margin=1in}10\usepackage{pythontex}11\usepackage{hyperref}12\usepackage{float}1314\title{Room Acoustics Analysis\\Reverberation and Sound Field Modeling}15\author{Acoustics Engineering Laboratory}16\date{\today}1718\begin{document}19\maketitle2021\begin{abstract}22This technical report presents computational analysis of room acoustics including reverberation time calculations using Sabine and Eyring equations, sound absorption modeling, and acoustic parameter optimization.23\end{abstract}2425\section{Introduction}2627Room acoustics determines sound perception quality in enclosed spaces. The reverberation time $T_{60}$ is the primary metric.2829\begin{pycode}30import numpy as np31import matplotlib.pyplot as plt32plt.rcParams['text.usetex'] = True33plt.rcParams['font.family'] = 'serif'34plt.rcParams['font.size'] = 103536# Room parameters37room_length, room_width, room_height = 15.0, 10.0, 4.038room_volume = room_length * room_width * room_height39floor_area = room_length * room_width40ceiling_area = floor_area41wall_area = 2 * (room_length + room_width) * room_height42total_surface = floor_area + ceiling_area + wall_area43c = 343 # m/s4445frequencies = np.array([125, 250, 500, 1000, 2000, 4000])46materials = {47'Concrete': np.array([0.01, 0.01, 0.02, 0.02, 0.02, 0.03]),48'Carpet': np.array([0.08, 0.24, 0.57, 0.69, 0.71, 0.73]),49'Acoustic Tiles': np.array([0.29, 0.44, 0.60, 0.77, 0.86, 0.84]),50'Glass': np.array([0.35, 0.25, 0.18, 0.12, 0.07, 0.04]),51}5253fig, ax = plt.subplots(figsize=(8, 5))54for material, alpha in materials.items():55ax.semilogx(frequencies, alpha, 'o-', label=material, linewidth=1.5)56ax.set_xlabel('Frequency (Hz)')57ax.set_ylabel('Absorption Coefficient $\\alpha$')58ax.set_title('Sound Absorption Coefficients')59ax.legend(loc='upper right', fontsize=8)60ax.grid(True, alpha=0.3)61plt.tight_layout()62plt.savefig('absorption_coefficients.pdf', dpi=150, bbox_inches='tight')63plt.close()64\end{pycode}6566\begin{figure}[H]67\centering68\includegraphics[width=0.85\textwidth]{absorption_coefficients.pdf}69\caption{Frequency-dependent absorption coefficients for common materials.}70\end{figure}7172\section{Sabine Reverberation Time}7374The Sabine equation: $T_{60} = \frac{0.161 V}{A}$7576\begin{pycode}77alpha_walls = materials['Concrete']78alpha_floor = materials['Carpet']79alpha_ceiling = materials['Acoustic Tiles']8081total_absorption = wall_area * alpha_walls + floor_area * alpha_floor + ceiling_area * alpha_ceiling82RT60_sabine = 0.161 * room_volume / total_absorption8384fig, ax = plt.subplots(figsize=(8, 5))85ax.semilogx(frequencies, RT60_sabine, 'b-o', linewidth=2, label='Sabine $T_{60}$')86ax.axhline(y=0.5, color='g', linestyle='--', label='Optimal (Speech)')87ax.axhline(y=1.5, color='r', linestyle='--', label='Optimal (Music)')88ax.set_xlabel('Frequency (Hz)')89ax.set_ylabel('Reverberation Time $T_{60}$ (s)')90ax.set_title('Sabine Reverberation Time vs Frequency')91ax.legend()92ax.grid(True, alpha=0.3)93plt.tight_layout()94plt.savefig('rt60_sabine.pdf', dpi=150, bbox_inches='tight')95plt.close()96\end{pycode}9798\begin{figure}[H]99\centering100\includegraphics[width=0.85\textwidth]{rt60_sabine.pdf}101\caption{Sabine reverberation time across frequency bands.}102\end{figure}103104\section{Eyring Reverberation Time}105106\begin{pycode}107alpha_avg = total_absorption / total_surface108RT60_eyring = 0.161 * room_volume / (-total_surface * np.log(1 - alpha_avg))109110fig, ax = plt.subplots(figsize=(8, 5))111ax.semilogx(frequencies, RT60_sabine, 'b-o', linewidth=2, label='Sabine')112ax.semilogx(frequencies, RT60_eyring, 'r-s', linewidth=2, label='Eyring')113ax.set_xlabel('Frequency (Hz)')114ax.set_ylabel('$T_{60}$ (s)')115ax.set_title('Comparison of Sabine and Eyring')116ax.legend()117ax.grid(True, alpha=0.3)118plt.tight_layout()119plt.savefig('rt60_comparison.pdf', dpi=150, bbox_inches='tight')120plt.close()121\end{pycode}122123\begin{figure}[H]124\centering125\includegraphics[width=0.85\textwidth]{rt60_comparison.pdf}126\caption{Comparison of Sabine and Eyring predictions.}127\end{figure}128129\section{Sound Pressure Level Distribution}130131\begin{pycode}132idx_1k = 3133A_1k = total_absorption[idx_1k]134alpha_avg_1k = alpha_avg[idx_1k]135R_room = A_1k / (1 - alpha_avg_1k)136L_W, Q = 90, 2137r = np.linspace(0.5, 15, 100)138139direct_field = Q / (4 * np.pi * r**2)140reverb_field = 4 / R_room141L_p = L_W + 10 * np.log10(direct_field + reverb_field)142r_c = np.sqrt(Q * R_room / (16 * np.pi))143144fig, ax = plt.subplots(figsize=(8, 5))145ax.plot(r, L_p, 'b-', linewidth=2, label='Total SPL')146ax.axvline(x=r_c, color='k', linestyle='--', label=f'$r_c$ = {r_c:.2f} m')147ax.set_xlabel('Distance from Source (m)')148ax.set_ylabel('Sound Pressure Level (dB)')149ax.set_title('SPL Distribution in Room')150ax.legend()151ax.grid(True, alpha=0.3)152plt.tight_layout()153plt.savefig('spl_distribution.pdf', dpi=150, bbox_inches='tight')154plt.close()155\end{pycode}156157\begin{figure}[H]158\centering159\includegraphics[width=0.85\textwidth]{spl_distribution.pdf}160\caption{Sound pressure level as function of distance.}161\end{figure}162163\section{Room Modes}164165\begin{pycode}166modes = []167for nx in range(0, 5):168for ny in range(0, 5):169for nz in range(0, 5):170if nx == 0 and ny == 0 and nz == 0:171continue172f = (c/2) * np.sqrt((nx/room_length)**2 + (ny/room_width)**2 + (nz/room_height)**2)173if f <= 200:174modes.append(f)175modes.sort()176177fig, ax = plt.subplots(figsize=(10, 3))178ax.eventplot([modes], lineoffsets=0.5, linelengths=0.8, colors='blue')179ax.set_xlabel('Frequency (Hz)')180ax.set_title('Room Mode Distribution (0-200 Hz)')181ax.set_xlim([0, 200])182ax.set_ylim([0, 1])183ax.set_yticks([])184plt.tight_layout()185plt.savefig('room_modes.pdf', dpi=150, bbox_inches='tight')186plt.close()187188f_schroeder = 2000 * np.sqrt(RT60_sabine[idx_1k] / room_volume)189\end{pycode}190191\begin{figure}[H]192\centering193\includegraphics[width=0.9\textwidth]{room_modes.pdf}194\caption{Room mode distribution in low-frequency range.}195\end{figure}196197\section{Clarity Indices}198199\begin{pycode}200t_ir = np.linspace(0, 2, 1000)201decay_rate = 6.91 / RT60_sabine[idx_1k]202impulse_response = np.exp(-decay_rate * t_ir)203204idx_50 = np.argmin(np.abs(t_ir - 0.050))205energy_early = np.trapz(impulse_response[:idx_50]**2, t_ir[:idx_50])206energy_late = np.trapz(impulse_response[idx_50:]**2, t_ir[idx_50:])207C50 = 10 * np.log10(energy_early / energy_late)208209fig, ax = plt.subplots(figsize=(8, 5))210ax.plot(t_ir * 1000, 20*np.log10(impulse_response + 1e-10), 'b-', linewidth=1.5)211ax.axvline(x=50, color='g', linestyle='--', label='50 ms')212ax.set_xlabel('Time (ms)')213ax.set_ylabel('Level (dB)')214ax.set_title('Room Impulse Response Energy Decay')215ax.legend()216ax.grid(True, alpha=0.3)217ax.set_xlim([0, 500])218plt.tight_layout()219plt.savefig('impulse_response.pdf', dpi=150, bbox_inches='tight')220plt.close()221\end{pycode}222223\begin{figure}[H]224\centering225\includegraphics[width=0.85\textwidth]{impulse_response.pdf}226\caption{Room impulse response energy decay curve.}227\end{figure}228229\section{Optimization}230231\begin{pycode}232ceiling_coverage = np.linspace(0, 1, 50)233RT60_optimized = []234for coverage in ceiling_coverage:235alpha_opt = coverage * materials['Acoustic Tiles'] + (1 - coverage) * materials['Concrete']236A_opt = wall_area * alpha_walls + floor_area * alpha_floor + ceiling_area * alpha_opt237RT60_optimized.append(0.161 * room_volume / A_opt[idx_1k])238RT60_optimized = np.array(RT60_optimized)239240target_RT60 = 0.8241optimal_idx = np.argmin(np.abs(RT60_optimized - target_RT60))242optimal_coverage = ceiling_coverage[optimal_idx]243244fig, ax = plt.subplots(figsize=(8, 5))245ax.plot(ceiling_coverage * 100, RT60_optimized, 'b-', linewidth=2)246ax.axhline(y=target_RT60, color='r', linestyle='--', label=f'Target = {target_RT60} s')247ax.set_xlabel('Acoustic Tile Coverage (\\%)')248ax.set_ylabel('$T_{60}$ (s)')249ax.set_title('$T_{60}$ Optimization')250ax.legend()251ax.grid(True, alpha=0.3)252plt.tight_layout()253plt.savefig('rt60_optimization.pdf', dpi=150, bbox_inches='tight')254plt.close()255\end{pycode}256257\begin{figure}[H]258\centering259\includegraphics[width=0.85\textwidth]{rt60_optimization.pdf}260\caption{$T_{60}$ optimization via ceiling treatment.}261\end{figure}262263\section{Results}264265\begin{pycode}266print(r'\begin{table}[H]')267print(r'\centering')268print(r'\caption{Room Acoustic Parameters}')269print(r'\begin{tabular}{@{}ccc@{}}')270print(r'\toprule')271print(r'Frequency (Hz) & $T_{60}$ Sabine (s) & $T_{60}$ Eyring (s) \\')272print(r'\midrule')273for i, f in enumerate(frequencies):274print(f'{f} & {RT60_sabine[i]:.2f} & {RT60_eyring[i]:.2f} \\\\')275print(r'\bottomrule')276print(r'\end{tabular}')277print(r'\end{table}')278\end{pycode}279280Key metrics: $r_c = \py{round(r_c, 2)}$ m, $C_{50} = \py{round(C50, 1)}$ dB, $f_s = \py{round(f_schroeder, 1)}$ Hz.281282\section{Conclusions}283284The room configuration provides acceptable reverberation for multipurpose use. Optimal ceiling coverage is \py{round(optimal_coverage * 100, 0)}\%.285286\end{document}287288289