Acouvero
Herunterladen
TECHNICAL DOC · v0.3.1

Raumakustik,
von der Messung
zum Plan.

Acouvero ist ein Werkzeug zur Raumakustik-Analyse und Maßnahmenplanung für iPhone / iPad. Dieses Dokument richtet sich an Leser mit Interesse an Akustik-Engineering oder Client-Implementierung — Kernalgorithmen, Geometriesystem, Messmethoden, Empfehlungssystem und Engineering-Hinweise.

Oktavbänder
6Bänder
Raumformen
4Geometrien
Reflexionen
1–3Ordnungen
§ 01

Überblick

Eingabe: Der Nutzer gibt Raummaße / Form / Materialien, Lautsprecher- und Hörposition ein — oder die Geometrie wird per LiDAR (RoomPlan) erfasst.

Ausgabe
  • Lokalisierung früher Reflexionen
  • Vollständige RT60 / EDT / C50 / C80 / D50 (gemessen + simuliert)
  • Liste der Raummoden-Frequenzen
  • Panel-Layout (Position, Anzahl, Produkt-SKU)
  • 3D-Visualisierung + Reflexionsenergie-Heatmap
  • PDF-Export in Montagehandbuch-Qualität
  • Messung über das iPhone-Mikrofon (Sweep / Klatschen)

Rechteckige, L-, U-förmige und beliebige einfache Polygon-Räume werden unterstützt; die Berechnung nutzt das echte Polygon, nicht die Bounding Box.

§ 02

Akustikmodell

2.1 Sabine RT60

Die klassische Sabine-Formel:

SABINE · RT60 $$ RT_{60} = \frac{0.161 \cdot V}{\sum_i S_i \alpha_i} $$
$V$
Raumvolumen (m³); bei Polygonen Shoelace-Fläche × Höhe, abzüglich Hindernissen (Stützen / Träger).
$\sum_i S_i \alpha_i$
Fläche × Absorptionsgrad je Fläche. Koeffizienten über 6 Oktavbänder (125 / 250 / 500 / 1k / 2k / 4k Hz).
$0.161$
= 24·ln(10)/c, mit c = 343 m/s (20 °C).

Die App liefert 5 Ausstattungs-Presets (leer / harte Oberflächen / Möbel / bereits behandelt / Studio), je mit Absorptionskurve pro Band. Auch das Ziel-RT60 ist eine 6-Band-Kurve, passend zu Normen wie EBU Tech 3276 / THX, die einen längeren Tiefbass-Nachhall zulassen.

2.2 Image-Source-Methode (ISM)

Erste Reflexionen per Spiegelung: Quelle an der Wand spiegeln; der Schnittpunkt der Strecke „Spiegelquelle → Hörer“ mit der Wand ist der Reflexionspunkt.

  • Rechteckiger Raum: Spiegelung an allen 6 Ebenen — geschlossene Lösung.
  • Nicht rechteckig (PolygonReflectionCalculator): jedes Wandsegment aus RoomPolygon.walls() spiegeln, Parameter s ∈ [0, 1] prüfen, Reflexions-XY muss im Polygon liegen.

Mehrfachreflexionen (Ordnung 1–3) implementiert MultiOrderReflectionCalculator nach dem rekursiven Ansatz von pyroomacoustics:

  1. Alle Wandsequenzen [s₁, …, sₙ] aufzählen, benachbarte Wände verschieden
  2. Spiegelquellen-Iteration: S₀ = Quelle, Sₖ = mirror(Sₖ₋₁, sₖ)
  3. Rückverfolgung vom Hörer: Sₙ → Hörer trifft sₙ in Pₙ; Sₙ₋₁ → Pₙ trifft sₙ₋₁ in Pₙ₋₁; rekursiv zurück
  4. Jeder Schnittpunkt muss im gültigen Wandbereich liegen und t ∈ (0, 1)
NÄHERUNG Bei nicht rechteckigen Räumen nutzt Multi-Order die Bounding-Box-Näherung („Geisterreflexionen“ nahe konkaven Ecken). Die Analyse verwirft jeden Pfad, dessen Reflexionspunkt > 0,3 m von jedem echten Wandsegment entfernt ist; nur gültige Pfade gehen in die Flutter-/Slapback-Erkennung.

2.3 Pfadenergie

Breitband-Energie als Funktion von Reflexionsanzahl und Distanzdämpfung:

PATH ENERGY $$ E_{rel} = (1 - \bar{\alpha})^N \cdot \frac{d_{direct}^2}{d_{total}^2} $$
  • α wird auf [0, 0.99] begrenzt, damit α = 1 kein log(0) oder pow(negativ, N) = NaN erzeugt
  • Distanzdämpfung folgt der sphärischen Ausbreitung 1/r²
  • Umrechnung in dB über 10·log₁₀ (Energiedomäne)

Die Energie pro Band wird für die 6 Oktavbänder separat berechnet (Koeffizient aus finishProfile.absorptionByBand).

2.4 RT60-Schätzung (gemessen)

ImpulseResponseEstimator:

  • Matched Filtering: der aufgenommene 0,45-s-Sweep wird invers gefiltert (ESS / Farina) zu einem Impuls, ~+40 dB effektiver SNR
  • rmsEnvelope: gleitende RMS-Hüllkurve
  • Schroeder-Rückwärtsintegration: E_back(t) = ∫ₜ^∞ s²(τ) dτ, mit 10·log₁₀ normiert ergibt die EDC-Kurve
  • Lineare Steigungsregression: bevorzugt T30 [−5, −35 dB] je SNR, sonst T20 [−5, −25] oder T10 [−5, −15]
  • RT₆₀ = −60 / Steigung

RT60 pro Band: auf den gefilterten Samples Bandpass an ISO-Oktavmitten (250 / 500 / 1k / 2k / 4k), Q = √2, dann Schroeder je Band.

2.5 RIR-Simulation

SimulatedRIRGenerator wandelt Mehrfachreflexionspfade in diskrete Impulse in einem 8 kHz × 0,5 s PCM-Puffer:

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

Den Direktschall-Impuls hinzufügen, dann Schroeder-Integration für EDT / RT60 / C50 / C80 / D50.

Vorher- / Nachher-Vergleich Jeder Pfad wird durch die Panels der berührten Wände gedämpft — ein „behandelter“ RIR. Die UI schaltet A/B um, zeigt die EDT-/C50-Verbesserung, und AVAudio faltet ein trockenes Signal zum hörbaren Vergleich.

2.6 Raummoden

Modale Frequenzen eines rechteckigen Raums:

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} $$

Klassifiziert nach Anzahl der von null verschiedenen nₓ, n_y, n_z: 1 = axial, 2 = tangential, 3 = schräg.

Nicht rechteckige Räume schätzen Moden über die Bounding Box (exakte Moden brauchen FEM); in der UI ausgewiesen.

§ 03

Geometriesystem

3.1 Unterstützte Formen

  • Rechteck — Breite × Länge × Höhe
  • L-Form — eine nw × nl-Kerbe an einer Ecke entfernen
  • U-Form — eine nw × nl-Kerbe mittig an einer Wand entfernen
  • Benutzerdefiniert — beliebiges einfaches Polygon (≥ 3, ≤ 24 Ecken)

Alle nicht rechteckigen Formen werden über RoomPolygon.from(shape:, bboxWidth:, bboxLength:) zur CCW-Eckenliste. Die Akustik nutzt diese Ecken direkt, nicht die Bounding Box.

3.2 Polygon-Geometrie-Werkzeuge

  • Fläche — Shoelace-Formel
  • Umfang — Summe der Kantenlängen
  • contains(x, y) — Ray-Casting mit Rand-Epsilon (verhindert Fehler an Ecken)
  • clamped(point) — Rechtecke nutzen den schnellen Pfad [0, w] × [0, l]; andere das echte [minₓ, maxₓ] × [min_y, max_y] aus polygon.boundingBox, prüfen polygon.contains und Binärsuche zum Bbox-Zentrum, falls außerhalb
  • walls() — zerlegt das Polygon in nach Innennormalen klassifizierte Segmente (leftWall / rightWall / frontWall / backWall), sodass der rechteckige Panel-Empfehler wiederverwendet wird
  • PolygonValidator.isSimple — prüft ein nicht selbstschneidendes einfaches Polygon

3.3 RoomPlan-Scan

Auf iOS 17+ wird RoomCaptureSession genutzt; CapturedRoomMapper bildet den Scan auf ScannedRoom ab (wallSegments + openings + furniture). Koordinaten-Mapping:

ARKit (x, y, z) → y ist vertikal App (x, y, z) → z ist vertikal Wand-Endpunkte (z=0 Boden) App.x = ARKit.x App.y = ARKit.z App.z = 0 Öffnung / Möbel-Zentrum  App.x = ARKit.x App.y = ARKit.z App.z = ARKit.y

Gescannte nicht rechteckige Räume durchlaufen RectangularRoomSimplifier.polygonShapeFromScan, das wallSegments zu Polygon-Ecken verkettet. RoomPlan-Endpunkte haben typ. 3–8 cm Fehler; eine 12-Segment-Schleife kann 5 cm akkumulieren, daher 12 cm Schließ-Epsilon. Schließt die Kette nicht, Rückfall auf die Bounding Box und Aufforderung zum erneuten Scan.

3.4 Freier Vertex-Editor

FreeVertexEditorView erlaubt das Ziehen von Ecken auf einem SwiftUI-Canvas:

  • Langes Drücken zum Löschen (bei ≥ 3 Ecken)
  • Das Ziehen speichert den letzten gültigen Zustand in dragSnapshot; eine selbstschneidende Position wird still zurückgesetzt
  • 0,05-m-Raster-Einrastung
  • Ein Rand von max(0,5, bbox × 0,2) m außerhalb der Bbox erlaubt das Ziehen über die Bbox hinaus (die Elternansicht vergrößert room.width / length automatisch)
§ 04

Hörzonen & Multi-Listener

AcousticConfiguration.listeners unterstützt 1..N Hörpositionen. Die Analyse führt die Image-Source-Methode je Hörer aus und fügt Reflexionspunkte in ein Array zusammen (primärer Hörer zuerst). Der Empfehler gewichtet jede Wand nach Punktanzahl (cap = max(6, speakerCount × listenerCount)); mehrere Sitze an einer Wand treiben sie ans Budgetlimit.

UI-Darstellung
  • In 3D nutzen sekundäre Hörer Opacity 0,45 + Scale 0,75
  • Draufsicht (RoomPlanView): primäre Punkte volle Farbe r=5, sekundäre Opacity 0,45 r=3
  • Die Liste (RecommendationView) zeigt nur primäre Punkte; Fußnote „+ N Reflexionen bereits berücksichtigt“

Mehrfachreflexionen / RIR / Heatmap werden weiterhin einmal für den primären Hörer berechnet (O(speakers × surfaces³) je Hörer ist zu schwer, RIR ist eine Einzelpunkt-Metrik).

§ 05

Empfehlungssystem

PanelPlacementRecommender liefert [PanelRecommendation], je mit: Position (links / rechts / Decke / vorn / hinten / Ecke), Anzahl, Priorität (essenziell / stark / empfohlen / optional), effectivenessMultiplier, targetReflectionPointId.

5.1 Proportionale Zuteilung (größter Rest)

Das alte gierige add() ließ Wände verhungern: linke Wand verbrauchte das Budget → rechte 0; bei knappem Budget auch Decke / vorn / hinten. Neu: Methode des größten Rests:

  • Raw-Desired je Wand berechnen (Punktanzahl + Raumtiefe + Anwendungsfall)
  • floor(raw × budget / total) als Anfangszuteilung
  • Wände mit raw > 0 erhalten ≥ 1 Panel (keine nachgefragte Wand verhungert)
  • falls Summe > Budget, vom kleinsten Bruchrest aufwärts kürzen
  • Links/Rechts-Symmetrie: bei raw[0] == raw[1] alloc[0] == alloc[1] erzwingen
  • Restbestand nach größtem Bruchteil umverteilen

5.2 Anwendungsfall-Vorlagen

Ohne platzierte Lautsprecher gelten anwendungsspezifische Vorlagen:

  • Besprechungsraum: Decke 35 % + Rückwand 20 % + je Seitenwand 12 %
  • Podcast: direkt vor dem Mikrofon 25 % + je Seite 18 % + Decke 20 %
  • Studio: symmetrische Vier-Wand-Dämpfung + erzwungene 4 Eck-Bassfallen
  • Allgemeines Hören: symmetrische Basis + Hinweis, Lautsprecher hinzuzufügen

5.3 Physikalische Muss-Maßnahmen umgehen das Budget

Eck-Bassfallen werden bei dichten 80–150-Hz-Moden auf 4 erzwungen und umgehen das totalPanel-Limit. Grund: In Ecken ist der Schalldruck am höchsten, Bassfallen dort ~1,5× effizienter — physikalische Notwendigkeit.

5.4 Hörnahe Gewichtung

Ein Nachlauf markiert Empfehlungen innerhalb 1,5 m eines Hörers als .nearListener, setzt effectivenessMultiplier ×1,15 und vermerkt dies in Titel / Begründung.

§ 06

Messung

6.1 ESS-Sweep

Nach Farinas Methode:

  • Logarithmischer Sweep 180 Hz → 4 kHz, 0,45 s
  • Inversfilter (makeInverseSweep) = Zeitumkehr + 1/freq-Amplitudenkompensation
  • Aufnahme via AVAudioRecorder als AAC m4a (44,1 kHz mono)
  • Zurücklesen → Matched Filter → analyzeImpulse
Abtastraten-Schutz Wenn die reale Aufnahmerate ≠ 44,1 kHz ist (USB-C-Interfaces / manche Bluetooth-Configs), wird Matched Filtering übersprungen und die UI warnt vor geringer Zuverlässigkeit.

6.2 Klatsch-Impuls

Ohne Wiedergabe — der Nutzer klatscht einmal kräftig, 3 s Ausklang werden aufgenommen. Direkt zu analyzeImpulse (kein Matched Filter nötig; ein Klatschen ist bereits ein schmaler Impuls). Deckt das 125-Hz-Band ab, das der Sweep (ab 180 Hz) verfehlt.

6.3 Gemessen vs. simuliert

MeasuredVsSimulatedCard nimmt das letzte gemessene RT60 und zeigt die Abweichung zum simulierten RT60:

< 15%Modell und Messung stimmen überein
15–30%gewisse Abweichung (nicht modellierte Möbel / Materialien)
> 30%große Abweichung — Geometrie / Materialien prüfen

6.4 Umgebungsrauschen & Kalibrierung

AmbientNoiseEstimator nimmt ein stilles Segment auf, um Grundrauschen dBFS / Spektrum zu berechnen und den SNR zu bewerten. DelayCalibrationService bestimmt per Nahfeld-Wiedergabe + Aufnahme die Wiedergabe-zu-Aufnahme-Latenz (typ. 80–150 ms).

§ 07

Visualisierung & Ausgabe

7.1 3D-Ansicht

Room3DController rendert mit SceneKit: Wände / Boden / Decke / Lautsprecher (dünnes Gehäuse + Akzent + Kanal-Pille) / Hörer (FE-Glyph + Stiel) / Hindernisse (transluzente SCNBox) / empfohlene Panels / Mehrfachreflexions-Pfadsegmente / Reflexionsenergie-Overlay.

DESIGN · TECHNISCHE ZEICHNUNG „Technische-Zeichnung“-Stil (feine Kanten, konstante Beleuchtung, kein PBR), bewusst anders als fotorealistisches 3D.

7.2 Reflexionsenergie-Heatmap

ReflectionEnergyMapGenerator akkumuliert die Energie jedes Pfads auf das uCells × vCells-Raster der Wand (Standard 12×6). Eine Karte je Wand, in 3D als Farbtemperatur-Layer (blau → rot).

EnergyHeatmapRenderer wandelt das Raster in ein UIImage: bikubisches Upsampling + Magma-Colormap + Alpha nach Absolutenergie.

7.3 RIR-Faltungs-Vorschau

RIRPreviewPlayer (AVAudioEngine + AVAudioPlayerNode) faltet ein beliebiges trockenes Signal (Stimme / Drums / Piano) mit dem simulierten RIR — hörbar „unbehandelt vs. behandelt“.

Zeitbereichs-Faltung RIRConvolver.convolve(dry:rir:) direkt O(N × M) (N = trockene Samples, M = RIR), Peak-normiert auf 0,9 gegen Clipping.

7.4 PDF-Montagehandbuch

ReportExporter rendert ein A4-PDF (595 × 842 pt) via UIGraphicsPDFRenderer:

  • Raumübersicht + 3D-Schnappschuss
  • 6-Band-RT60-Balkendiagramm gemessen vs. Ziel
  • Reflexionspunkt-Tabelle + Moden-Tabelle + Risikoübersicht
  • Empfohlene-Panel-Tabelle + Einkaufsliste (BOM)
  • Geist-Schrift + PingFangSC-Fallback (CoreText cascadeList, damit CJK nicht als □□□ erscheint)

7.5 Projekt-Persistenz

ProjectStore (Actor) schreibt ~/Library/Application Support/AcouVero/projects.json: [RoomProject], je mit Room + Lautsprechern + Hörern + Empfehlungen + panelCountOverrides.

MeasurementStore (Actor) schreibt measurements.json: [MeasurementResult], per roomId mit dem Projekt verknüpft.

Beide nutzen elementweise Decode-Wiederherstellung (Throwable<T>-Wrapper) — ein defekter Datensatz lässt nicht die ganze Liste scheitern.

§ 08

Engineering-Hinweise

8.1 SwiftUI + @Observable

Das ViewModel (AcouVeroViewModel) nutzt Swift 5.9 @Observable — Statusfelder direkt beobachtet, kein Combine. AcousticAnalysis-Ergebnisse werden per Equatable-Vergleich von AcousticConfiguration gecacht:

AcouVeroViewModel.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 Actor-Isolation

ProjectStore, MeasurementStore und RoomPlanService sind actors, die IO / Async natürlich serialisieren. Die UI nutzt async / await; der Hauptthread wird nie durch Disk-IO blockiert.

8.3 AVAudio-Lebenszyklus

AudioSessionManager zentralisiert die Session-Kategorie (.playback für RIR-Vorschau, .playAndRecord für Messung). AVAudioSession.interruptionNotification erkennt Anruf / Siri und stoppt die Engine, isPlaying zurückgesetzt.

8.4 Task-Abbruch

Die Faltungs-Wiedergabe ist ein Hintergrund-Task; schnelle Taps lösen pendingPlayTask?.cancel() plus Task.isCancelled-Doppelprüfung aus, um Out-of-order-MainActor-Schreibvorgänge zu verhindern.

8.5 Testabdeckung

AllShapesAndUseCasesTests nutzt das Swift-Testing-Framework für die volle Matrix — jede Form × jeder Anwendungsfall × diverse Hörer-/Lautsprecher-Kombis — und prüft:

  • analysis.reflectionPaths.count >= 1
  • analysis.warnings enthält den Näherungshinweis für nicht rechteckige Räume
  • Empfehlungssumme entspricht dem Budget
  • der Allokator garantiert sum ≤ Budget und Symmetrie
  • Polygon-Schließung / Ecken &lt; 3 und weitere Randfälle
§ 09

Bekannte Grenzen

  1. Multi-Order in nicht rechteckigen Räumen via Bounding Box — Flutter-/Slapback-Risiko 2./3. Ordnung nahe konkaven Ecken kann abweichen. Erste Ordnung nutzt das echte Polygon.
  2. Raummoden in nicht rechteckigen Räumen via Bounding Box geschätzt — exakte Moden brauchen FEM.
  3. Messung mit iPhone-Mikrofon — unkalibriert; nicht-flacher Frequenzgang / Empfindlichkeit. Zuverlässigkeit immer .low, als Quervergleich zur geometrischen Schätzung.
  4. Einzelquellen-ISM-Annahme — ignoriert Gehäusebeugung, Horn-Richtwirkung u. a.
  5. Keine Bassfallen-Modellierung — Probleme unter 80 Hz liegen außerhalb des Sabine-Modells und brauchen dedizierte Tieftonbehandlung.
  6. AR-Scan-Genauigkeit — RoomPlan-Endpunkte typ. 3-8 cm Fehler; 12-Segment-Schleife kann 5+ cm akkumulieren. Wanddicke nicht modelliert.
§ 10

Referenzen

  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.
Lieber die einfache Version?

„Warum dein Raum die Musik umschreibt“

Deep Read lesen