Hazar Ekin Uçan

Ausgewählte Projekte

VR Prosodic Speech Analysis System

Ein fertiges System, das die Sprechweise während einer VR-Übung misst und anhand eigener ruhiger und dringlich gesprochener Referenzaufnahmen bewertet.

Rolle
Python-Engine und API
Kontext
Eigenes Projekt
Zeitraum
2026
Stack
Python · FastAPI · Faster-Whisper · Praat / parselmouth · librosa

Was es ist Ein System, das die stimmliche Erregung während einer VR-Übung misst und in Echtzeit einen persönlich normierten Score anzeigt.

Was ich gebaut habe Die Python-Engine für die Analyse und der FastAPI-Dienst, den die VR-Schicht aufruft.

Meine Rolle

Ich habe die Python-Engine für die Analyse entworfen und geschrieben. Dazu gehören die Aufnahme, Transkription und Wortzeitstempel mit Faster-Whisper, die Auswertung prosodischer Merkmale mit Praat und librosa, die persönliche Kalibrierung anhand zweier Referenzen, die Score-Berechnung, die Qualitätsprüfungen und die Sitzungsprotokolle. Auch den FastAPI-Dienst, den die VR-Schicht aufruft, habe ich geschrieben. Jeder Commit im Repository ist von mir. Das System läuft von Anfang bis Ende auf einem einzigen Windows-PC, mit dem Headset über Quest Link.

01

Messen, wie jemand spricht

Wie jemand während einer VR-Übung spricht, verrät etwas, das der reine Aufgabenscore nicht erfasst.

Wenn jemand in VR eine simulierte Prozedur durchgeht, weiß das System bereits, ob die Schritte erledigt wurden. Es weiß nichts darüber, wie die Person dabei geklungen hat. Tonhöhe, Lautstärke, Tempo und Pausen liefern diese Information. Ich wollte daraus eine Zahl machen, während die Übung noch läuft.

Eine feste Schwelle funktioniert nicht. Wenn ich sage, alles über 180 Hz oder 70 dB gilt als erhöht, misst das System am Ende die Person statt ihren Zustand. Wer von Natur aus laut spricht, überschreitet diese Linie schon im ruhigen Zustand. Wer leise spricht, überschreitet sie selbst unter echtem Druck nie. Eine feste akustische Schwelle müsste auf unterschiedliche Stimmen passen. Ich wollte aber eine Veränderung innerhalb derselben Stimme erkennen.

  • Hardware Ein Windows-PC, Meta Quest 3 über Quest Link, Ton vom virtuellen Oculus-Mikrofon mit 16 kHz mono
  • Interaktion Eine Controller-Taste: gedrückt halten zum Aufnehmen, loslassen zum Auswerten
  • Grenze Keine Audioanalyse in C# nachgebaut. Eine Umsetzung, in Python
  • Latenz Die Auswertung kommt zurück, während die Übung noch läuft
  • Grundsatz Lieber nichts zurückgeben als einen schlechten Score

02

Zwei Referenzaufnahmen statt einer festen Schwelle

Jede Person bekommt eine eigene Skala. Beide Endpunkte werden aus ihrer Stimme bestimmt.

Vor der Übung nimmt jede Person zwei kurze Sätze auf. Den ersten spricht sie in normalem Ton als Baseline, den zweiten deutlich dringlicher als Upperline. Der Abstand zwischen den beiden Aufnahmen bildet für jedes Merkmal den persönlichen Bewertungsbereich.

Spätere Aufnahmen werden innerhalb dieses persönlichen Bereichs eingeordnet: null entspricht der Baseline, eins der Upperline. Eine laute und eine leise sprechende Person erhalten denselben Score, wenn sie sich relativ zu ihren eigenen Referenzen gleich stark in Richtung Dringlichkeit verändert haben.

Diagramm: persönliche Kalibrierung

Sprecher A

lauter, höhere Stimmlage

Baseline 112 Hz 0

Upperline 196 Hz 100

Sprecher B

leiser, tiefere Stimmlage

Baseline 78 Hz 0

Upperline 121 Hz 100

Abstand mit Vorzeichen

bei Dringlichkeit langsamer

Baseline 5.4 syll/s 0

Upperline 4.1 syll/s 100

Die ruhige Baseline und die deutlich dringlicher gesprochene Upperline bilden die persönliche Skala. Der Score beschreibt die Veränderung zwischen diesen Referenzen statt einen absoluten Pegel. Die beiden Personen oben haben unterschiedliche Tonhöhen und erhalten dennoch denselben Score. Die dritte Achse zeigt einen negativen Abstand: Liegt die Upperline bei einem Merkmal unter der Baseline, läuft die Skala in die andere Richtung. Die Werte dienen nur dazu, das Verfahren zu erklären. Es sind keine Messungen.

Besonders wichtig war mir, das Vorzeichen der Spanne beizubehalten. Die meisten Menschen sprechen schneller, wenn sie Dringlichkeit ausdrücken; ihre Upperline der Artikulationsrate liegt also über ihrer Baseline. Manche sprechen stattdessen langsamer und bedachter. Die Formel behandelt das nicht als Fehler, der korrigiert werden müsste. Sie behält die Richtung, die diese Person tatsächlich gezeigt hat. Die Spanne ist dann einfach negativ, und der Fortschritt darauf wird genauso berechnet.

app_speech_integrated.py · compare_with_two_anchors()

raw_progress = (
  current_number - baseline_number
) / gap

# Baseline'ın ters yönündeki değişim panik puanı üretmez.
score_progress = max(raw_progress, 0.0)

# Upperline'ı aşmak mümkündür. 1.25 sınırı, tek özelliğin
# bütün skoru aşırı şişirmesini engeller.
score_progress = min(score_progress, 1.25)

weighted_progress += score_progress * weight
used_weight += weight

Fortschritt entlang einer persönlichen Spanne. Negative Spannen funktionieren unverändert, Bewegung in die Gegenrichtung ergibt null, ein Merkmal ist gedeckelt und kann nicht dominieren.

Der Score wird aus sechs Merkmalen berechnet. Jedes hat ein Gewicht und eine Mindestspanne. Die Mindestspanne ist der kleinste Abstand zwischen den beiden Ankern einer Person, der noch als echter Unterschied zählt und nicht als Rauschen.

Die sechs bewerteten prosodischen Merkmale mit ihrem Gewicht im Endscore und dem Mindestabstand, der zwischen den beiden Kalibrierankern einer sprechenden Person nötig ist.

MerkmalGewichtMindestspanneQuelle
F0-Median0.255 HzPraat Tonhöhe
Mittlere Intensität0.202 dBPraat Intensität
Artikulationsrate0.200.30 syll/sWhisper Wortzeitstempel
Maximale Intensität0.153 dBPraat Intensität
Tonhöhenumfang (p90−p10)0.105 HzPraat Tonhöhe
Pausenanteil0.100.03Whisper Wortzeitstempel
Eine echte Aufnahme, ausgewertet mit der Python-Engine: Wellenform, Wortgrenzen aus Faster-Whisper und ermittelte Tonhöhenwerte. Die Aufnahme stammt vom Laptopmikrofon, nicht vom Headset, und enthält nur eine Äußerung. Sie zeigt die Ausgabe der Analyse, bestätigt aber nicht deren Genauigkeit.

Für die zeitliche Auswertung nutze ich die Wortzeitstempel von Faster-Whisper statt einer energiebasierten Sprachaktivitätserkennung. Energiebasierte VAD kann eine Pause nicht von einem stillen Raum unterscheiden, und ein verrauschtes Signal vom Headset-Mikrofon erschwert die Erkennung zusätzlich. Wortgrenzen aus dem Transkript sind eine deutlich bessere Grundlage dafür, zu sagen, wo das Sprechen tatsächlich aufgehört hat. Silben werden über das Zählen türkischer Vokale genähert. Das ist eine dokumentierte Näherung und kein echter Silbentrenner, und sie reicht, um eine Person mit sich selbst zu vergleichen.

Das System ist bewusst in zwei Schichten gebaut, mit einer HTTP-Brücke dazwischen.

Diagramm: Systemarchitektur

VR-Schicht

Quest 3 Quest Link · Controller-Taste
Unity-Szene Interaktion und Ergebnispanel
FastAPI /health · /start · /stop

Python-Analyse-Engine

  1. 01 Aufnahme 16 kHz mono
  2. 02 Transkription · Faster-Whisper
  3. 03 Prosodische Merkmale extrahieren
  4. 04 Qualitätsprüfungen
  5. 05 Persönliche Kalibrierung
  6. 06 Score 0-100

Läuft auch ohne angeschlossenes Headset

Zwei Schichten und eine Brücke. Die VR-Seite kümmert sich um Interaktion und Anzeige, die gesamte Analyse bleibt in Python. Damit müssen Audiobibliotheken nicht in C# nachgebaut werden und es gibt genau eine maßgebliche Umsetzung der Messung. Die Analyseschritte werden bei jeder Aufnahme nacheinander ausgeführt.

Diese Trennung ist sinnvoll, weil die gesamte Messung in Python bleibt. Zu Praat, librosa und Faster-Whisper gibt es in C# kein Gegenstück. Einen Teil davon in das VR-Projekt zu portieren hätte eine zweite Umsetzung der Messung erzeugt, und ich hätte beide dauerhaft aufeinander abstimmen müssen.

03

Irreführende Scores vermeiden

Ein großer Teil der Entwicklungsarbeit steckt in der Entscheidung, wann kein Ergebnis ausgegeben werden darf.

Einer Zahl auf einem Bildschirm vertraut man schnell. Deshalb muss klar sein, wann das System überhaupt eine ausgeben darf. Die folgenden Prüfungen sind für mich der wichtigste Teil dieser Entwicklung.

Diagramm: Scoring und Qualitätsprüfungen

  1. 01

    Aufnahme brauchbar?

    Clipping bei Spitze ≥ 0.99, zu leise unter 0.02, stimmhafte Frames unter 20%

    Warnen und die Aufnahme erneut anfordern

  2. 02

    Kalibriersatz gesprochen?

    Transkript wird mit dem erwarteten Satz verglichen

    Referenzaufnahme wiederholen

  3. 03

    Unterscheidet sich das Merkmal genug?

    Baseline und Upperline müssen sich um die Mindestspanne des Merkmals unterscheiden

    Das Merkmal aus dem Scoring nehmen

  4. 04

    Bleibt genug vom Profil übrig?

    Mindestens zwei Merkmale mit einem Gesamtgewicht von mindestens 0.40

    Die Kalibrierung ablehnen

Wenn alle Prüfungen bestanden sind

  • Veränderung innerhalb des persönlichen Bereichs, mit der bei dieser Person gemessenen Richtung
  • Bewegung entgegen dieser Richtung trägt null bei
  • Ein einzelnes Merkmal ist bei 1.25 gedeckelt und kann so nicht dominieren
  • Gewichtet, dann auf 0-100 begrenzt
Vor der Score-Berechnung stehen vier Prüfungen. Für jede ist festgelegt, was bei einem Problem passiert. Das System gibt lieber kein Ergebnis aus als eine Zahl ohne belastbare Grundlage. Ein Merkmal auszuschließen, eine Kalibrierung abzulehnen oder eine Referenzaufnahme zu wiederholen ist dabei normal.

Die Prüfung auf Merkmalsebene ist die wichtigste. Unterscheiden sich Baseline und Upperline bei einem Merkmal nicht ausreichend, liefert es keine Information über die Veränderung dieser Person. Vielleicht hat sie beide Male auf derselben Tonhöhe gesprochen. Dieses Merkmal würde nur Rauschen in die Bewertung bringen. Deshalb wird es ausgeschlossen. Die übrigen Merkmale, bei denen ein Unterschied erkennbar ist, werden neu gewichtet und zum Score verrechnet.

Fallen zu viele Merkmale weg, reicht das Profil nicht mehr für eine Bewertung. Bleiben weniger als zwei Merkmale oder liegt ihr Gesamtgewicht unter 0.40, wird die Kalibrierung abgelehnt. Die Referenzaufnahmen müssen dann wiederholt werden.

Die Aufnahmequalität wird vor all dem geprüft. Clipping bei einer Spitze von 0.99 oder darüber, eine Spitze unter 0.02 oder weniger als 20% stimmhafte Frames lösen jeweils eine Warnung aus. Es gibt noch eine feinere. Meldet die Sprachaktivitätserkennung, dass 98% oder mehr des Fensters aktives Sprechen sind, ist das meist ein lauter Raum, der als durchgehendes Reden gehört wird, und die daraus abgeleiteten Zeitmerkmale sind nicht vertrauenswürdig.

baseline_manager.py · evaluate_recording_quality()

if speech_window > 0:
  active_ratio = active_duration / speech_window

  if active_ratio >= 0.98:
      warnings.append(
          "Kayıdın neredeyse tamamı aktif konuşma olarak algılandı. "
          "Gürültü nedeniyle VAD/sessizlik tespiti güvenilir olmayabilir."
      )

Diese Prüfung soll Raumgeräusche erkennen, nicht die sprechende Person bewerten.

Eine Prüfung mag ich noch besonders. Der Kalibriersatz selbst wird verifiziert: das Transkript dessen, was die Person gesagt hat, wird mit dem Satz verglichen, den sie sagen sollte. Eine Baseline, die aufgenommen wurde, während jemand mit der Person nebenan geredet hat, sollte nicht stillschweigend zur Referenz werden, an der jeder spätere Score gemessen wird.

04

Das fertige System

Vom Tastendruck bis zum Score läuft alles auf einem Rechner.

Das System, von Anfang bis Ende

  1. Nimmt Ton vom Quest-Mikrofon über Quest Link auf
  2. Die Controller-Taste steuert /start und /stop auf der FastAPI-Brücke
  3. Liefert das Transkript und die Wortzeitstempel von Faster-Whisper
  4. Extrahiert sechs prosodische Merkmale je Aufnahme: F0-Median und Umfang, mittlere und maximale Intensität, Artikulationsrate, Pausenanteil
  5. Erstellt aus Baseline und Upperline ein persönliches Kalibrierprofil und prüft es vor der Nutzung
  6. Gibt einen persönlich normierten Score von 0-100 an das VR-Panel zurück
  7. Schreibt JSON je Äußerung, eine Sitzungs-CSV und einen Sitzungsbericht für spätere Auswertungen
Drei Fotos: Arbeit am Analysecode an einem Laptop, das getragene Quest-3-Headset mit der Unity-Szene auf einem Wandbildschirm, und das Projektposter bei der Präsentation im Labor.
Die Teile, die in keinem Code-Listing auftauchen: die Arbeit an der Analyse-Engine, das Headset im Einsatz mit laufender Unity-Szene, und das präsentierte Projekt. Die Beispielwerte auf dem Poster sind illustrativ und keine gemessenen Ergebnisse.

Die Analyse-Engine läuft auch ohne angeschlossenes Headset. So habe ich sie entwickelt und kann sie weiterhin testen: Eine WAV-Datei und ein Satz reichen, um die gesamte Analyse auszuführen. Die VR-Schicht startet nur die Aufnahme und zeigt das Ergebnis an.

Wo die Grenzen liegen

Der prosodische Score zeigt, wie weit sich die Sprechweise von der eigenen ruhigen Referenz in Richtung der dringlichen Referenz verändert hat. Er erklärt nicht, warum. Müdigkeit, eine Erkältung, eine erhobene Stimme in einem lauten Raum und echte Dringlichkeit können dieselben Merkmale in dieselbe Richtung verändern. Das Signal erlaubt keine Unterscheidung zwischen diesen Ursachen. Der Score ist ausdrücklich kein klinisches Maß. Der Code sagt das an der Stelle, an der er ein Ergebnis ausgibt, und ich würde es überall dort weiter sagen, wo das eingesetzt wird. Für die Tempomerkmale wird die Silbenzahl anhand der türkischen Vokale näherungsweise bestimmt. Sie reicht, um eine Person mit sich selbst zu vergleichen, und sie reicht nicht, um Personen untereinander zu vergleichen.

Belege auf dieser Seite: Quellcode · Architektur · Systementwurf

Offen für Gespräche über Robotik, Automatisierung und Software für physische Systeme.