Acouvero
Baixar
TECHNICAL DOC · v0.4.0

Acústica de salas,
de ponta a ponta — da
medição ao plano.

O Acouvero é uma ferramenta de análise de acústica de salas e planejamento de tratamento para iPhone / iPad. Este documento é para leitores interessados na engenharia acústica ou na implementação do cliente — cobrindo os algoritmos centrais, o sistema de geometria, os métodos de medição, o motor de recomendações e notas de engenharia.

Bandas de oitava
6bandas
Formatos de sala
4geometrias
Reflexões
1–3ordens
§ 01

Visão geral

Entrada: o usuário informa o tamanho / formato / materiais de acabamento da sala, as posições dos alto-falantes e da posição de audição — ou a geometria da sala é medida com a trena em AR (sem necessidade de LiDAR) ou capturada por um escaneamento com LiDAR (RoomPlan).

Saída
  • Localização de pontos de reflexão inicial
  • RT60 (medido + simulado) mais EDT / C50 / C80 / D50 (derivados da RIR simulada)
  • Lista de frequências dos modos da sala
  • Plano de disposição dos painéis (posição, quantidade, SKU do produto)
  • Visualização 3D + mapa de calor da energia das reflexões
  • Exportação de PDF em nível de manual de instalação
  • Medição no dispositivo via microfone do iPhone (varredura / palma)

Há suporte para salas retangulares, em L, em U e com qualquer polígono simples; as reflexões de primeira ordem e os cálculos de área / contenção usam o polígono real; as reflexões de 2ª/3ª ordem e os modos da sala são aproximados pela caixa delimitadora (ver §9).

§ 02

Modelo acústico

2.1 Sabine RT60

A clássica fórmula de Sabine:

SABINE · RT60 $$ RT_{60} = \frac{0.161 \cdot V}{\sum_i S_i \alpha_i} $$
$V$
Volume da sala (m³); para polígonos, área Shoelace × altura, menos obstáculos como colunas / vigas.
$\sum_i S_i \alpha_i$
Área da superfície × coeficiente de absorção por face. Os coeficientes usam 6 bandas de oitava (125 / 250 / 500 / 1k / 2k / 4k Hz).
$0.161$
= 24·ln(10)/c, com c = 343 m/s (20 °C).

O app traz 4 predefinições de acabamento (cômodo vazio de superfícies duras / acabamento duro típico / ambiente com estofados / ambiente já tratado), cada uma com uma curva de absorção por banda; a estimativa de RT60 em valor único do topo e o orçamento de painéis usam um coeficiente médio de absorção das bandas médias-altas, enquanto a curva Sabine de 6 bandas alimenta a exibição por banda. O RT60 alvo também é uma curva de 6 bandas (não um valor único), em conformidade com normas como EBU Tech 3276 / THX, que permitem uma cauda de reverberação mais longa nas baixas frequências.

2.2 Método das Fontes de Imagem (ISM)

As reflexões de primeira ordem usam espelhamento: espelha-se a fonte em relação a uma parede; a interseção do segmento “fonte espelhada → ouvinte” com a parede é o ponto de reflexão.

  • Sala retangular: espelhar em todos os 6 planos (4 paredes + piso + teto) — forma fechada.
  • Não retangular (PolygonReflectionCalculator): espelha cada segmento de parede de RoomPolygon.walls() e valida o parâmetro s ∈ [0, 1] dentro do segmento (reflexões de piso / teto exigem ainda que o XY da reflexão esteja dentro do polígono); caminhos de primeira ordem também passam por uma verificação de oclusão 2D — qualquer trecho fonte→ponto→ouvinte que cruze outro segmento de parede é descartado.

Reflexões de múltiplas ordens (ordens 1–3) são implementadas pelo MultiOrderReflectionCalculator seguindo a abordagem recursiva do pyroomacoustics:

  1. Enumera todas as sequências de paredes [s₁, …, sₙ], com paredes adjacentes distintas
  2. Iteração da fonte imagem: S₀ = source, Sₖ = mirror(Sₖ₋₁, sₖ)
  3. Traçado reverso a partir do ouvinte: a reta Sₙ → ouvinte cruza sₙ em Pₙ; a reta Sₙ₋₁ → Pₙ cruza sₙ₋₁ em Pₙ₋₁; recursão até o início
  4. Cada interseção deve estar dentro do intervalo válido da parede e com t ∈ (0, 1) no segmento
APROXIMAÇÃO Em salas não retangulares, o multi-ordem usa a aproximação por bounding box (“reflexões fantasma” perto de cantos côncavos). A camada de análise descarta qualquer caminho cujo ponto de reflexão esteja a > 0,3 m de todos os segmentos de parede reais; só os caminhos válidos restantes alimentam a detecção de flutter / slapback.

2.3 Energia do caminho

Energia de banda larga em função do número de reflexões e da atenuação pela distância:

PATH ENERGY $$ E_{rel} = (1 - \bar{\alpha})^N \cdot \frac{d_{direct}^2}{d_{total}^2} $$
  • α é limitado a [0, 0.99] para que α = 1 não produza log(0) ou pow(negativo, N) = NaN, o que contaminaria todo o caminho
  • A atenuação pela distância segue o espalhamento esférico 1/r²
  • A conversão para dB usa 10·log₁₀ (domínio da energia)

A energia por banda é calculada separadamente para as 6 bandas de oitava (cada uma usando o coeficiente da respectiva banda de finishProfile.absorptionByBand).

2.4 Estimativa de RT60 (medida)

ImpulseResponseEstimator:

  • Filtragem casada: a varredura gravada de 0,45 s passa por filtragem inversa (ESS / Farina) e é comprimida em um único impulso, ganhando ~+32 dB de SNR efetiva
  • rmsEnvelope: envoltória RMS de janela deslizante
  • Integração reversa de Schroeder: E_back(t) = ∫ₜ^∞ s²(τ) dτ, normalizada com 10·log₁₀ para gerar a curva EDC
  • Regressão linear da inclinação: prefira T30 [−5, −35 dB] conforme o SNR, com fallback para T20 [−5, −25] ou T10 [−5, −15]
  • RT₆₀ = −60 / inclinação

RT60 por banda: sobre as amostras após o filtro casado, aplica-se passa-banda nos centros de oitava ISO (250 / 500 / 1k / 2k / 4k) com Q = √2, e então executa-se o Schroeder em cada banda.

2.5 Simulação de RIR

SimulatedRIRGenerator transforma os caminhos de reflexão multi-ordem em eventos de impulso discretos gravados em um buffer PCM de 8 kHz × 0,5 s:

SimulatedRIRGeneratorpseudocode
for path in reflectionPaths:
    t   = path.totalDistance / speedOfSound
    amp = 10^(path.relativeEnergyDB / 20)
    impulse[round(t * sampleRate)] += amp

Some o impulso do som direto e depois execute a integração reversa de Schroeder para extrair EDT / RT60 / C50 / C80 / D50.

Comparação antes / depois Cada caminho de reflexão é atenuado pelos painéis acumulados nas paredes que ele toca, produzindo um RIR “tratado”. A interface alterna entre A/B para mostrar a melhoria de EDT / C50, e o AVAudio faz a convolução de um sinal seco para comparar audivelmente o antes e o depois.

2.6 Modos da sala

Frequências modais de uma sala retangular:

ROOM MODES $$ f_{n_x, n_y, n_z} = \frac{c}{2} \sqrt{\left(\frac{n_x}{L_x}\right)^2 + \left(\frac{n_y}{L_y}\right)^2 + \left(\frac{n_z}{L_z}\right)^2} $$

Classificados por quantos dos índices nₓ, n_y, n_z são não nulos: 1 = axial, 2 = tangencial, 3 = oblíquo.

A enumeração cobre n ≤ 4 por eixo até 300 Hz. Salas não retangulares estimam os modos a partir da caixa delimitadora (modos exatos exigem FEM); isso é indicado explicitamente na interface.

§ 03

Sistema de geometria

3.1 Formatos suportados

  • Retângulo — width × length × height
  • Formato em L — remove um recorte nw × nl em um canto escolhido
  • Formato U — remove um recorte de nw × nl no meio de uma parede escolhida
  • Personalizado — qualquer polígono simples (≥ 3, ≤ 24 vértices)

Todos os formatos não retangulares viram uma lista de vértices em CCW via RoomPolygon.from(shape:, bboxWidth:, bboxLength:). As reflexões de primeira ordem, os cálculos de área / perímetro e de contenção usam esses vértices diretamente; um polígono personalizado inválido (< 3 / > 24 vértices, com autointerseção, área quase nula) degrada silenciosamente para o retângulo delimitador.

3.2 Utilitários de geometria de polígonos

  • Área — fórmula de Shoelace
  • Perímetro — soma dos comprimentos das arestas
  • contains(x, y) — ray-casting com fallback de epsilon na fronteira (evita falsos negativos nos cantos)
  • clamped(point) — retângulos usam o caminho rápido [0, w] × [0, l]; não retângulos usam o verdadeiro [minₓ, maxₓ] × [min_y, max_y] do polygon.boundingBox, testam polygon.contains e fazem busca binária em direção ao centro do bbox se estiver fora
  • walls() — divide o polígono em segmentos de parede classificados pela normal interna (agrupados automaticamente em leftWall / rightWall / frontWall / backWall), permitindo reutilizar o recomendador de painéis da versão retangular
  • PolygonValidator.isSimple — valida um polígono simples sem autointerseção

3.3 Escaneamento com RoomPlan

Usa-se a RoomCaptureSession (API do iOS 16+; no app, o escaneamento exige iOS 17), e o CapturedRoomMapper mapeia o escaneamento para um ScannedRoom (wallSegments + openings + furniture). Mapeamento de coordenadas:

ARKit (x, y, z) → y é vertical App (x, y, z) → z é vertical Extremidades da parede (z=0 piso) App.x = ARKit.x App.y = ARKit.z App.z = 0 Abertura / centro de móvel  App.x = ARKit.x App.y = ARKit.z App.z = ARKit.y

Os escaneamentos são classificados pela contagem de paredes: exatamente 4 segmentos de parede são tratados diretamente como retângulo; qualquer outro caso passa pelo RectangularRoomSimplifier.polygonShapeFromScan, encadeando os wallSegments em vértices de polígono. Os endpoints do RoomPlan têm erro típico de 3–8 cm; um loop de 12 segmentos pode acumular 5 cm, então o epsilon de fechamento é 12 cm. Se a cadeia não fechar, ele recorre ao bounding box e pede para o usuário escanear de novo.

3.4 Trena AR

Em dispositivos sem LiDAR, o ARTapeMeasureView (uma ARView do RealityKit com world tracking) assume: mire a cruz de mira na parede e toque duas vezes para registrar os pontos inicial / final, passando por largura → comprimento → altura, depois confirme para gerar uma sala retangular — com orientação sobre permissão de câmera e dicas para falha de rastreamento.

3.5 Editor de vértices livres

FreeVertexEditorView permite ao usuário arrastar vértices em um Canvas do SwiftUI:

  • Pressione e segure para excluir (quando o número de vértices > 3, de modo que restem ≥ 3)
  • Cada quadro do arrasto é validado com isSimple; uma nova posição com autointerseção simplesmente não é aplicada (o vértice fica onde está). Tocar em um espaço vazio insere um vértice na aresta mais próxima; há também um editor numérico por vértice e um botão de redefinir para o retângulo delimitador
  • Snap na grade de 0,05 m
  • Uma margem de max(0,5, bbox × 0,2) m fora da bbox permite que o usuário arraste vértices para além da bbox atual (a view pai aumenta automaticamente room.width / length)
§ 04

Zonas de audição e múltiplos ouvintes

AcousticConfiguration.listeners aceita 1..N posições de audição (com 0 ouvintes, uma posição primária padrão é sintetizada com um aviso; com 0 alto-falantes, os templates de caso de uso da §5.2 assumem o controle). A análise executa o método das fontes-imagem uma vez por ouvinte e mescla os pontos de reflexão em um único array (os pontos do ouvinte primário primeiro). O recomendador de painéis acústicos pondera cada parede pelo número de pontos de reflexão (cap = max(6, speakerCount × listenerCount)); vários assentos compartilhando a mesma parede naturalmente a empurram em direção ao teto do orçamento.

Visuais da UI
  • No 3D, os nós de secondary listener usam opacity 0,45 + scale 0,75
  • Na vista superior (RoomPlanView), os pontos de reflexão primários são r=5 em cor cheia, os secundários r=3 com opacidade 0,45
  • A lista de reflexões (RecommendationView) mostra apenas os pontos primários; as posições de audição secundárias recebem uma nota de rodapé “+ N reflexões já contabilizadas no plano”

Reflexões de múltiplas ordens / RIR / mapa de calor ainda são calculados uma única vez para o ouvinte principal (por ouvinte, O(speakers × surfaces³) é pesado demais, e o RIR é uma métrica de ponto único).

§ 05

Motor de recomendação

PanelPlacementRecommender gera [PanelRecommendation], cada item com: posição (parede esquerda / parede direita / teto / parede frontal / parede traseira / canto), quantidade, prioridade (essencial / forte / recomendado / opcional), effectivenessMultiplier, targetReflectionPointId.

5.1 Alocação proporcional (maiores restos)

O antigo add() guloso deixava paredes sem nada: a parede esquerda consumia o orçamento → a parede direita ficava com 0; com orçamentos apertados, o teto / a frente / o fundo também ficavam sem. A nova versão usa o método do maior resto (largest-remainder):

  • Calcular o desejado bruto de cada parede (contagem de pontos de reflexão + profundidade da sala + caso de uso)
  • floor(raw × budget / total) como alocação inicial
  • paredes com raw &gt; 0 recebem pelo menos 1 painel; somente quando o orçamento é menor que o número de paredes com demanda é que as superfícies são zeradas, começando pelas de menor prioridade
  • se a soma &gt; orçamento, corta a partir do menor resto fracionário
  • passagem de simetria esquerda/direita: se raw[0] == raw[1], força alloc[0] == alloc[1]
  • redistribuir qualquer sobra pela maior fração

5.2 Modelos por caso de uso

Sem alto-falantes posicionados, aplicam-se templates específicos por caso de uso:

  • Sala de reunião: teto 35% + parede do fundo 20% + cada parede lateral 12%
  • Podcast: diretamente à frente do microfone 25% + cada lado 18% + teto 20%
  • Estúdio: amortecimento simétrico nas quatro paredes + até 4 armadilhas de graves de canto dentro do orçamento (o verdadeiro desvio de orçamento só acontece no caminho de modos de baixa frequência densos da §5.3)
  • Audição geral: base simétrica + um aviso para adicionar alto-falantes

5.3 Os itens físicos indispensáveis contornam o orçamento

As armadilhas de graves de canto são forçadas a 4 quando os modos de 80–150 Hz são densos, ignorando o limite totalPanel. Motivo: os cantos têm a maior pressão sonora e as armadilhas de graves são ~1,5× mais eficientes ali do que nas paredes — uma necessidade física, não um item de orçamento.

5.4 Ponderação próxima ao ouvinte

Um pós-processamento marca as recomendações de parede a até 1,5 m de um ouvinte como .nearListener, define effectivenessMultiplier ×1,15 e indica no título / motivo que se trata de uma “zona de absorção sensível a curta distância”.

§ 06

Medição

6.1 Varredura ESS

Seguindo o método de Farina:

  • 180 Hz → 4 kHz, varredura logarítmica de 0,45 s
  • Filtro inverso (makeInverseSweep) = reversão temporal + um envelope de amplitude de +6 dB/oitava (crescente com a frequência, para compensar o espectro rosa do ESS)
  • Gravação via AVAudioRecorder em Linear PCM sem perdas (16 bits mono .caf, faixa dinâmica de ~96 dB — codecs perceptuais não têm lugar na medição de impulso; a taxa de amostragem segue a sessão de áudio — 44,1 kHz no microfone integrado, os 48 kHz nativos em microfones de medição USB)
  • Leitura de volta → filtro casado → analyzeImpulse
Alinhamento de taxa de amostragem O WAV de varredura, a varredura inversa e a gravação são todos gerados na taxa de amostragem real da sessão de áudio (makeInverseSweep(sampleRate:) é parametrizado) — a filtragem casada está sempre ativa, tanto a 44,1 kHz no microfone integrado quanto a 48 kHz em microfones de medição USB.

6.2 Impulso de palma

Sem reprodução — o usuário bate uma palma forte dentro de uma janela de 1 s; são gravados 4,5 s no total (~3,5 s de cauda). O sinal vai direto para analyzeImpulse (não precisa de filtragem casada; uma palma já é um impulso estreito). Isso cobre a banda de oitava de 125 Hz, que a varredura (a partir de 180 Hz) não alcança.

6.3 Medido vs simulado

MeasuredVsSimulatedCard obtém o RT60 medido mais recente do projeto e mostra o desvio em relação ao RT60 simulado da geometria atual:

< 15%modelo e medição concordam
15–30%certa divergência (possivelmente móveis / materiais não modelados)
> 30%grande divergência — verifique novamente a geometria / os materiais

6.4 Ruído ambiente & calibração

AmbientNoiseEstimator grava 3 s de silêncio (aparando 100 ms em cada extremidade) para o ruído de fundo da sala: média de banda larga / pico em dBFS, mais uma classificação de silêncio em 5 níveis (o dBFS é apenas relativo até uma calibração de SPL, depois da qual passa a ser exibido dB SPL). A calibração de latência de campo próximo reutiliza a mesma varredura ESS: segure o telefone a até 30 cm do alto-falante, meça o atraso do início da gravação até o pico do impulso (incluindo um pre-roll proposital de 250 ms), idealmente em 2–3 execuções — uma dispersão das últimas 3 leituras abaixo de 5 ms indica confiança alta; abaixo de 20 ms, média. A latência fica vinculada à rota atual de entrada + saída e se autoinvalida quando qualquer uma das duas muda; as medições de campo distante mostram o atraso de propagação já com ela subtraída.

6.5 Microfones de medição USB e roteamento de saída

O seletor de entrada da página de medição lista o microfone integrado e entradas USB class-compliant (ex.: miniDSP UMIK-1 / UMIK-2); um listener de routeChangeNotification retorna ao microfone integrado quando o externo desaparece. As taxas de amostragem de gravação e da varredura seguem a sessão (UMIK-1 = 48 kHz). Arquivos de calibração REW .txt são importados diretamente (interpretando Sens Factor / SERNO, interpolação linear no domínio de frequência logarítmica, clamp nas extremidades; o arquivo de 90° é recomendado para medição de salas) — a correção apenas desloca a exibição do nível por banda, nunca a inclinação de decaimento do RT60.

Calibração única de SPL: encaixe um calibrador de nível sonoro (padrão 94 dB @ 1 kHz) sobre o microfone, o app amostra 3 s de nível para derivar o deslocamento dBFS → SPL, e as leituras passam a exibir dB SPL reais. A calibração (curva + deslocamento) é vinculada ao UID da porta de entrada e persistida em ~/Library/Application Support/mic_calibration.json; ao trocar de entrada, a interface avisa em laranja que a calibração não se aplica — importe e calibre novamente.

A reprodução passa pelo seletor de rota do sistema (um wrapper de AVRoutePickerView, colocado nos cards de varredura / calibração de campo próximo); a sessão libera AirPlay / Bluetooth A2DP / HFP para que os tons de teste toquem por alto-falantes externos, e volta para o alto-falante do aparelho quando nenhum está conectado. A entrada de gravação fica sempre explicitamente fixada na escolha do usuário (microfone USB ou integrado), para que o microfone de um dispositivo Bluetooth não roube a entrada no meio da reprodução e contamine a medição.

§ 07

Visualização e saída

7.1 Visualização 3D

Room3DController renderiza com SceneKit: paredes / piso / teto / nós de alto-falantes (cabinet fino + accent tick + channel pill) / ouvinte (FE glyph + drop stem) / obstáculos (SCNBox translúcido) / painéis recomendados (mockups de painéis por parede) / segmentos de caminho de reflexão de múltiplas ordens / sobreposição de mapa de calor de energia de reflexão.

DESIGN · DESENHO TÉCNICO A aparência é um “estilo de desenho técnico” (arestas hairline, iluminação constante, sem PBR), deliberadamente distinta do 3D fotorrealista.

7.2 Mapa de calor de energia de reflexão

O ReflectionEnergyMapGenerator acumula a energia de cada caminho de múltiplas ordens na grade uCells × vCells da parede atingida (padrão 12×6). Um mapa de energia por parede, sobreposto em 3D como uma camada de cor de energia (azul → ciano → verde → amarelo → vermelho).

EnergyHeatmapRenderer transforma a grade em uma UIImage: células em estilo de blocos de 16 px cada (sem interpolação entre as células, mantendo as bordas da grade legíveis; a suavização na parede vem da filtragem bilinear de textura do SceneKit) + um degradê personalizado de 5 paradas (azul → ciano → verde → amarelo → vermelho) + alfa mapeado linearmente de 0,20 a 0,85 conforme a posição da energia em uma escala fixa de −30…0 dB (−∞ totalmente transparente).

7.3 Prévia da convolução RIR

RIRPreviewPlayer usa AVAudioEngine + AVAudioPlayerNode para convolver um sinal seco sintetizado proceduralmente (corda dedilhada / sequência de palmas / fala semelhante a vogais — sem amostras embutidas) com a RIR simulada e reproduzi-lo, para que os usuários ouçam a diferença entre “sem tratamento” e “com tratamento”.

A convolução no domínio do tempo RIRConvolver.convolve(dry:rir:) é O(N × M) direta (N = amostras do sinal dry, M = amostras do RIR), normalizada pelo pico em 0,9 para evitar clipping.

7.4 Manual de instalação em PDF

ReportExporter renderiza um PDF A4 (595 × 842 pt) via UIGraphicsPDFRenderer:

  • Visão geral da sala + captura 3D
  • Gráfico de barras de RT60 em 6 bandas, estimativa de Sabine vs. alvo (o RT60 medido não entra no PDF)
  • Tabela de pontos de reflexão + tabela de modos + resumo de riscos
  • Tabela de painéis recomendados (a BOM da lista de compras é exibida no app, não no PDF)
  • Fonte Geist + fallback PingFangSC (cascadeList do CoreText, para o CJK não renderizar como □□□)

7.5 Persistência de projetos

ProjectStore (um actor) grava ~/Library/Application Support/Acouvero/projects.json: [RoomProject], cada um contendo o Room completo + speakers + listeners + recommendations + panelCountOverrides. No primeiro lançamento, os dados migram automaticamente do diretório legado FindEcho/ (FindEcho é o codinome interno anterior à mudança de nome, mantido deliberadamente nos símbolos do código).

MeasurementStore (um actor) grava ~/Library/Application Support/Acouvero/measurements.json: [MeasurementResult], vinculado a um projeto pelo roomId.

Ambos usam recuperação de decodificação em nível de elemento (um wrapper Throwable<T>) — um registro corrompido não derruba a lista inteira.

MicCalibrationStore grava ~/Library/Application Support/mic_calibration.json (raiz do diretório, sem subdiretório): a curva de calibração do REW + offset de SPL, vinculada ao UID da porta de entrada — trocar de entrada exige uma nova importação / calibração.

§ 08

Notas de engenharia

8.1 SwiftUI + @Observable

A ViewModel (FindEchoViewModel) usa a macro @Observable do Swift 5.9 — os campos de estado são observados diretamente, sem Combine. Os resultados da AcousticAnalysis são armazenados em cache por meio de uma comparação Equatable de AcousticConfiguration:

FindEchoViewModel.analysisswift
var analysis: AcousticAnalysis {
    let cfg = configuration
    if let cached = cachedAnalysis, cachedConfiguration == cfg {
        return cached
    }
    let result = analysisService.analyze(cfg)
    cachedConfiguration = cfg
    cachedAnalysis = result
    return result
}

8.2 Isolamento de actors

ProjectStore e MeasurementStore são actors, serializando a lógica de IO / assíncrona de forma natural; RoomPlanService é uma classe @MainActor. Os chamadores da UI usam async / await, então a thread principal nunca é bloqueada por IO de disco.

8.3 Ciclo de vida do AVAudio

AudioSessionManager centraliza a categoria da sessão (.playback para a prévia do RIR, .playAndRecord para a medição). A proteção contra interrupções cobre os dois caminhos: no lado da medição, um InterruptionMonitor dentro de AudioMeasurementService observa AVAudioSession.interruptionNotification — uma ligação / Siri durante uma varredura, palma ou medição de ruído ambiente descarta o resultado com um erro; no lado da prévia, RIRPreviewPlayer também observa, parando automaticamente o nó do player e limpando isPlaying. Uma mudança de rota de áudio no meio da medição também invalida a execução.

8.4 Cancelamento de Task

A reprodução da convolução é uma tarefa em segundo plano; toques rápidos no botão disparam pendingPlayTask?.cancel() mais uma dupla verificação de Task.isCancelled para evitar escritas fora de ordem na MainActor.

8.5 Cobertura de testes

AllShapesAndUseCasesTests usa o framework Swift Testing para rodar a matriz completa — cada formato × cada caso de uso (um único ouvinte; os alto-falantes são um par estéreo ou um único central por caso de uso) — verificando:

  • analysis.reflectionPaths.count >= 1
  • analysis.warnings inclui a nota de aproximação para salas não retangulares
  • o total de painéis recomendados é não negativo (totalPanelCount ≥ 0; sem asserção de correspondência com o orçamento)
  • polígonos personalizados que se autointersectam fazem fallback com segurança (sem crash, degradando para um retângulo)
  • vértices &lt; 3 e outros fallbacks de casos de borda

8.6 Plataforma e localização

Destino de implantação iOS 17.0, iPhone + iPad; zero dependências de terceiros (sem pacotes SPM / CocoaPods) — apenas frameworks do sistema (SwiftUI / SceneKit / ARKit / RoomPlan / AVFoundation / Accelerate). A localização usa um catálogo .xcstrings: chinês como idioma de origem, mais English / Français / Deutsch / Español / Português (Brasil) — 6 idiomas no total, alternáveis no app ou seguindo o sistema.

§ 09

Limitações conhecidas

  1. Multi-ordem em salas não retangulares usa a caixa delimitadora — o risco de flutter / slapback de 2ª/3ª ordem perto de cantos côncavos pode sair impreciso. Os pontos de primeira ordem em si usam o polígono real.
  2. Os modos da sala em salas não retangulares são estimados a partir do bounding box — modos exatos exigem FEM.
  3. Medição com o microfone integrado do iPhone — não calibrado; resposta de frequência / sensibilidade não plana. A confiança é sempre marcada como .low, usada como referência cruzada com a estimativa geométrica. Com um microfone de medição USB (miniDSP UMIK-1 / UMIK-2) e o arquivo de calibração do REW carregado, os níveis por banda são corrigidos pela curva de calibração; uma calibração de referência única de 94 dB SPL então exibe os níveis ambiente e de medição como dB SPL absolutos (somente dBFS até lá).
  4. Hipótese de fonte única do ISM — ignora a difração da caixa, a diretividade da corneta e outras características de alto-falantes reais.
  5. Sem modelagem de armadilhas de graves — problemas abaixo de 80 Hz ficam fora do modelo de Sabine e precisam de tratamento dedicado para baixas frequências.
  6. Precisão da varredura AR — os endpoints do RoomPlan erram tipicamente 3-8 cm; um loop de 12 segmentos pode acumular mais de 5 cm. A espessura das paredes não é modelada.
§ 10

Referências

  1. Sabine, W. C. (1922). Collected Papers on Acoustics. Harvard University Press.
  2. Allen, J. B., & Berkley, D. A. (1979). Image method for efficiently simulating small-room acoustics. JASA, 65(4), 943–950.
  3. Schroeder, M. R. (1965). New method of measuring reverberation time. JASA, 37(3), 409–412.
  4. Farina, A. (2000). Simultaneous measurement of impulse response and distortion with a swept-sine technique. Audio Engineering Society Convention 108.
  5. Scheibler, R., Bezzam, E., & Dokmanić, I. (2018). Pyroomacoustics: A Python package for audio room simulation and array processing algorithms. ICASSP 2018.
  6. EBU Tech 3276. Listening conditions for the assessment of sound programme material.
  7. ITU-R BS.1116. Methods for the subjective assessment of small impairments in audio systems.
  8. BB93 — Acoustic design of schools (UK).
  9. THX Pro Cinema Certification requirements.
Quer a versão em linguagem simples?

“Por que a sua sala reescreve a música que você ouve”

Leia o Deep Read