vitorcalvi commited on
Commit
0ab2c16
·
1 Parent(s): fe1a73f

hrv commit incomplete

Browse files
Files changed (1) hide show
  1. hrv.py +264 -0
hrv.py ADDED
@@ -0,0 +1,264 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import numpy as np
3
+ from scipy import signal
4
+ import soundfile as sf
5
+ import matplotlib.pyplot as plt
6
+ import io
7
+ import time
8
+ from datetime import datetime
9
+
10
+ def generate_test_tone(frequency, duration=1.0, sample_rate=44100):
11
+ t = np.linspace(0, duration, int(sample_rate * duration))
12
+ tone = np.sin(2 * np.pi * frequency * t)
13
+ return tone * np.hanning(len(tone))
14
+
15
+ def hearing_test(frequency, volume, ear_selection):
16
+ sample_rate = 44100
17
+ tone = generate_test_tone(float(frequency), 1.0, sample_rate)
18
+ volume_adjusted = tone * (10 ** (volume / 20))
19
+
20
+ stereo_tone = np.zeros((2, len(tone)))
21
+ if ear_selection == "Left":
22
+ stereo_tone[0] = volume_adjusted
23
+ elif ear_selection == "Right":
24
+ stereo_tone[1] = volume_adjusted
25
+ else:
26
+ stereo_tone[0] = stereo_tone[1] = volume_adjusted
27
+
28
+ output_path = f"test_tone_{frequency}Hz.wav"
29
+ sf.write(output_path, stereo_tone.T, sample_rate)
30
+ return output_path
31
+
32
+ def create_audiogram(left_ear_results, right_ear_results):
33
+ frequencies = [250, 500, 1000, 2000, 4000, 8000]
34
+ plt.figure(figsize=(10, 8))
35
+
36
+ plt.fill_between([125, 8000], -10, 25, color='#e6f3ff', alpha=0.3, label='Normal Hearing')
37
+ plt.fill_between([125, 8000], 25, 40, color='#b3d9ff', alpha=0.3, label='Mild Loss')
38
+ plt.fill_between([125, 8000], 40, 55, color='#80bfff', alpha=0.3, label='Moderate Loss')
39
+ plt.fill_between([125, 8000], 55, 70, color='#4da6ff', alpha=0.3, label='Moderate-Severe Loss')
40
+
41
+ plt.plot(frequencies, left_ear_results, 'x-', color='blue', label='Left Ear')
42
+ plt.plot(frequencies, right_ear_results, 'o-', color='red', label='Right Ear')
43
+
44
+ plt.xscale('log')
45
+ plt.xlim(125, 8000)
46
+ plt.ylim(70, -10)
47
+ plt.grid(True)
48
+ plt.xlabel('Frequency (Hz)')
49
+ plt.ylabel('Hearing Level (dB)')
50
+ plt.title('Audiogram Results')
51
+ plt.legend()
52
+
53
+ buf = io.BytesIO()
54
+ plt.savefig(buf, format='png')
55
+ plt.close()
56
+ return buf
57
+
58
+ def generate_audio(duration, selected_frequencies):
59
+ sample_rate = 44100
60
+ num_samples = int(float(duration) * sample_rate)
61
+ noise = np.random.normal(0, 1, num_samples)
62
+
63
+ if selected_frequencies:
64
+ frequencies = [int(f) for f in selected_frequencies]
65
+ for freq in frequencies:
66
+ depth = -40 if freq == 4000 else -30
67
+ width = freq / 10
68
+ nyquist = sample_rate / 2
69
+ freq_normalized = freq / nyquist
70
+ quality_factor = freq / width
71
+ b, a = signal.iirnotch(freq_normalized, quality_factor)
72
+ noise = signal.filtfilt(b, a, noise)
73
+ noise *= 10 ** (depth / 20)
74
+
75
+ noise = noise / np.max(np.abs(noise))
76
+ output_path = "notched_noise.wav"
77
+ sf.write(output_path, noise, sample_rate)
78
+ return output_path
79
+
80
+ class HRVMonitor:
81
+ def __init__(self):
82
+ self.recording = False
83
+ self.start_time = None
84
+ self.data = []
85
+
86
+ def start_recording(self):
87
+ self.recording = True
88
+ self.start_time = time.time()
89
+ self.data = []
90
+ return "Recording started..."
91
+
92
+ def stop_recording(self):
93
+ self.recording = False
94
+ return "Recording stopped."
95
+
96
+ def update_display(self):
97
+ if not self.recording:
98
+ return None
99
+
100
+ current_time = time.time() - self.start_time
101
+ base_rr = 1000 # Base RR interval (ms)
102
+ rr_intervals = base_rr + np.random.normal(0, 50, 10) # Add variability
103
+
104
+ # Calculate HRV metrics
105
+ rmssd = np.sqrt(np.mean(np.diff(rr_intervals) ** 2))
106
+ sdnn = np.std(rr_intervals)
107
+ lf_power = np.random.uniform(70, 85) # Simulated LF power
108
+ hf_power = np.random.uniform(15, 30) # Simulated HF power
109
+ lf_hf_ratio = lf_power / hf_power
110
+ hrv_score = min(100, max(1, 50 + (rmssd - 30) / 2))
111
+
112
+ metrics = {
113
+ 'time': current_time,
114
+ 'score': round(hrv_score),
115
+ 'rr': round(np.mean(rr_intervals)),
116
+ 'rmssd': round(rmssd),
117
+ 'sdnn': round(sdnn),
118
+ 'lf': round(lf_power),
119
+ 'hf': round(hf_power),
120
+ 'lf_hf': round(lf_hf_ratio, 1)
121
+ }
122
+
123
+ self.data.append(metrics)
124
+
125
+ return f"""
126
+ HRV Score: {metrics['score']}
127
+ RR: {metrics['rr']} ms
128
+ RMSSD: {metrics['rmssd']} ms
129
+ SDNN: {metrics['sdnn']} ms
130
+ LF: {metrics['lf']}%
131
+ HF: {metrics['hf']}%
132
+ LF/HF: {metrics['lf_hf']}
133
+ Recording time: {round(current_time)}s
134
+ """
135
+
136
+ def refresh_hrv(hrv_monitor):
137
+ return hrv_monitor.update_display() if hrv_monitor.recording else "Click Start to begin monitoring..."
138
+
139
+ def create_interface():
140
+ hrv_monitor = HRVMonitor()
141
+
142
+ with gr.Blocks(title="Hearing Test & HRV Monitor") as app:
143
+ with gr.Tabs():
144
+ # Hearing Test Tab
145
+ with gr.Tab("Hearing Test"):
146
+ gr.Markdown("## Hearing Test")
147
+ with gr.Row():
148
+ with gr.Column():
149
+ frequency = gr.Dropdown(
150
+ choices=["250", "500", "1000", "2000", "4000", "8000"],
151
+ value="1000",
152
+ label="Test Frequency (Hz)"
153
+ )
154
+ volume = gr.Slider(
155
+ minimum=-60,
156
+ maximum=0,
157
+ value=-20,
158
+ step=5,
159
+ label="Volume (dB)"
160
+ )
161
+ ear_select = gr.Radio(
162
+ choices=["Both", "Left", "Right"],
163
+ value="Both",
164
+ label="Ear Selection"
165
+ )
166
+ test_btn = gr.Button("Play Test Tone")
167
+ with gr.Column():
168
+ audio_output = gr.Audio(label="Test Tone")
169
+
170
+ with gr.Row():
171
+ with gr.Column():
172
+ left_thresholds = [gr.Number(value=0, label=f"{freq}Hz Left") for freq in [250, 500, 1000, 2000, 4000, 8000]]
173
+ with gr.Column():
174
+ right_thresholds = [gr.Number(value=0, label=f"{freq}Hz Right") for freq in [250, 500, 1000, 2000, 4000, 8000]]
175
+
176
+ generate_audiogram_btn = gr.Button("Generate Audiogram")
177
+ audiogram_output = gr.Image(label="Audiogram")
178
+
179
+ # White Noise Tab
180
+ with gr.Tab("White Noise Generator"):
181
+ gr.Markdown("## Notched White Noise Generator")
182
+ with gr.Row():
183
+ with gr.Column():
184
+ duration = gr.Slider(
185
+ minimum=1,
186
+ maximum=30,
187
+ value=5,
188
+ step=1,
189
+ label="Duration (seconds)"
190
+ )
191
+ frequencies = gr.CheckboxGroup(
192
+ choices=["250", "500", "1000", "2000", "4000", "8000"],
193
+ label="Frequencies to Notch (Hz)",
194
+ value=["4000", "2000"]
195
+ )
196
+ generate_noise_btn = gr.Button("Generate Noise")
197
+ with gr.Column():
198
+ noise_output = gr.Audio(label="Generated Noise")
199
+
200
+ # HRV Monitor Tab
201
+ with gr.Tab("HRV Monitor"):
202
+ with gr.Row():
203
+ with gr.Column():
204
+ start_btn = gr.Button("Start Recording")
205
+ stop_btn = gr.Button("Stop Recording")
206
+ hrv_display = gr.Textbox(
207
+ label="HRV Metrics",
208
+ value="Click Start to begin monitoring...",
209
+ lines=10,
210
+ interactive=False
211
+ )
212
+ gr.Markdown("""
213
+ ### Metrics Explanation:
214
+ - **HRV Score**: Overall heart rate variability (1-100)
215
+ - **RR**: Average time between heartbeats (ms)
216
+ - **RMSSD**: Root Mean Square of Successive Differences
217
+ - **SDNN**: Standard Deviation of NN intervals
218
+ - **LF/HF**: Balance between sympathetic and parasympathetic activity
219
+ """)
220
+
221
+ # Event handlers for hearing test
222
+ test_btn.click(
223
+ fn=hearing_test,
224
+ inputs=[frequency, volume, ear_select],
225
+ outputs=audio_output
226
+ )
227
+
228
+ generate_audiogram_btn.click(
229
+ fn=lambda *args: create_audiogram(args[:6], args[6:]).getvalue(),
230
+ inputs=left_thresholds + right_thresholds,
231
+ outputs=audiogram_output
232
+ )
233
+
234
+ # Event handler for noise generator
235
+ generate_noise_btn.click(
236
+ fn=generate_audio,
237
+ inputs=[duration, frequencies],
238
+ outputs=noise_output
239
+ )
240
+
241
+ # Event handlers for HRV monitor
242
+ start_btn.click(
243
+ fn=hrv_monitor.start_recording,
244
+ outputs=hrv_display
245
+ )
246
+
247
+ stop_btn.click(
248
+ fn=hrv_monitor.stop_recording,
249
+ outputs=hrv_display
250
+ )
251
+
252
+ # Auto-refresh HRV display
253
+ hrv_display.change(
254
+ fn=lambda: refresh_hrv(hrv_monitor),
255
+ inputs=None,
256
+ outputs=hrv_display,
257
+ every=1
258
+ )
259
+
260
+ return app
261
+
262
+ if __name__ == "__main__":
263
+ app = create_interface()
264
+ app.launch(share=False)