berangerthomas commited on
Commit
e900dee
·
1 Parent(s): c68cad6

fourier transform : Update defaults, add tooltip, improve phase filter

Browse files
fourier_transform.html CHANGED
@@ -29,8 +29,8 @@
29
  </div>
30
  <div class="control-group">
31
  <label for="freq1" class="control-label">Frequency (Hz)</label>
32
- <input type="range" min="0" max="50" value="5" step="1" class="slider" id="freq1">
33
- <div class="slider-value" id="freq1Value">5 Hz</div>
34
  </div>
35
  <div class="control-group">
36
  <label for="amp1" class="control-label">Amplitude</label>
@@ -55,8 +55,8 @@
55
  </div>
56
  <div class="control-group">
57
  <label for="freq2" class="control-label">Frequency (Hz)</label>
58
- <input type="range" min="0" max="50" value="15" step="1" class="slider" id="freq2">
59
- <div class="slider-value" id="freq2Value">15 Hz</div>
60
  </div>
61
  <div class="control-group">
62
  <label for="amp2" class="control-label">Amplitude</label>
@@ -81,8 +81,8 @@
81
  </div>
82
  <div class="control-group">
83
  <label for="freq3" class="control-label">Frequency (Hz)</label>
84
- <input type="range" min="0" max="50" value="25" step="1" class="slider" id="freq3">
85
- <div class="slider-value" id="freq3Value">25 Hz</div>
86
  </div>
87
  <div class="control-group">
88
  <label for="amp3" class="control-label">Amplitude</label>
@@ -107,8 +107,8 @@
107
  </div>
108
  <div class="control-group">
109
  <label for="freq4" class="control-label">Frequency (Hz)</label>
110
- <input type="range" min="0" max="50" value="35" step="1" class="slider" id="freq4">
111
- <div class="slider-value" id="freq4Value">35 Hz</div>
112
  </div>
113
  <div class="control-group">
114
  <label for="amp4" class="control-label">Amplitude</label>
@@ -125,8 +125,17 @@
125
  <!-- Global Settings -->
126
  <div class="wave-section" style="border-top: 2px solid var(--color-border); padding-top: var(--space-md); margin-top: var(--space-md);">
127
  <div class="control-group">
128
- <label for="numSamples" class="control-label">Samples (N)</label>
129
- <input type="range" min="64" max="512" value="256" step="1" class="slider" id="numSamples">
 
 
 
 
 
 
 
 
 
130
  <div class="slider-value" id="numSamplesValue">256</div>
131
  </div>
132
  <div class="control-group">
 
29
  </div>
30
  <div class="control-group">
31
  <label for="freq1" class="control-label">Frequency (Hz)</label>
32
+ <input type="range" min="0" max="50" value="4" step="1" class="slider" id="freq1">
33
+ <div class="slider-value" id="freq1Value">4 Hz</div>
34
  </div>
35
  <div class="control-group">
36
  <label for="amp1" class="control-label">Amplitude</label>
 
55
  </div>
56
  <div class="control-group">
57
  <label for="freq2" class="control-label">Frequency (Hz)</label>
58
+ <input type="range" min="0" max="50" value="8" step="1" class="slider" id="freq2">
59
+ <div class="slider-value" id="freq2Value">8 Hz</div>
60
  </div>
61
  <div class="control-group">
62
  <label for="amp2" class="control-label">Amplitude</label>
 
81
  </div>
82
  <div class="control-group">
83
  <label for="freq3" class="control-label">Frequency (Hz)</label>
84
+ <input type="range" min="0" max="50" value="12" step="1" class="slider" id="freq3">
85
+ <div class="slider-value" id="freq3Value">12 Hz</div>
86
  </div>
87
  <div class="control-group">
88
  <label for="amp3" class="control-label">Amplitude</label>
 
107
  </div>
108
  <div class="control-group">
109
  <label for="freq4" class="control-label">Frequency (Hz)</label>
110
+ <input type="range" min="0" max="50" value="16" step="1" class="slider" id="freq4">
111
+ <div class="slider-value" id="freq4Value">16 Hz</div>
112
  </div>
113
  <div class="control-group">
114
  <label for="amp4" class="control-label">Amplitude</label>
 
125
  <!-- Global Settings -->
126
  <div class="wave-section" style="border-top: 2px solid var(--color-border); padding-top: var(--space-md); margin-top: var(--space-md);">
127
  <div class="control-group">
128
+ <label for="numSamples" class="control-label">
129
+ Samples (N)
130
+ <span class="help-tooltip" title="Limiter N à des puissances de 2 (64, 128, 256, 512) garantit une meilleure résolution spectrale et évite le 'spectral leakage' qui crée des pics parasites dans le spectre de phase.">ℹ️</span>
131
+ </label>
132
+ <input type="range" min="64" max="512" value="256" step="64" class="slider" id="numSamples" list="powersOf2">
133
+ <datalist id="powersOf2">
134
+ <option value="64"></option>
135
+ <option value="128"></option>
136
+ <option value="256"></option>
137
+ <option value="512"></option>
138
+ </datalist>
139
  <div class="slider-value" id="numSamplesValue">256</div>
140
  </div>
141
  <div class="control-group">
src/css/fourier_transform.css CHANGED
@@ -99,3 +99,54 @@
99
  gap: var(--space-xs);
100
  }
101
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
99
  gap: var(--space-xs);
100
  }
101
  }
102
+
103
+ /* Tooltip for help icon */
104
+ .help-tooltip {
105
+ display: inline-block;
106
+ cursor: help;
107
+ margin-left: 4px;
108
+ font-size: 0.9em;
109
+ color: var(--color-primary);
110
+ position: relative;
111
+ vertical-align: middle;
112
+ }
113
+
114
+ .help-tooltip:hover::after {
115
+ content: attr(title);
116
+ position: absolute;
117
+ bottom: 100%;
118
+ left: 50%;
119
+ transform: translateX(-50%);
120
+ background-color: var(--color-bg-secondary);
121
+ color: var(--color-text);
122
+ padding: 8px 12px;
123
+ border-radius: 4px;
124
+ font-size: 0.75rem;
125
+ white-space: normal;
126
+ width: 300px;
127
+ max-width: 300px;
128
+ z-index: 1000;
129
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
130
+ border: 1px solid var(--color-border);
131
+ margin-bottom: 8px;
132
+ text-align: left;
133
+ line-height: 1.4;
134
+ }
135
+
136
+ .help-tooltip::before {
137
+ content: "";
138
+ position: absolute;
139
+ bottom: 100%;
140
+ left: 50%;
141
+ margin-left: -5px;
142
+ border-width: 5px;
143
+ border-style: solid;
144
+ border-color: transparent transparent var(--color-border) transparent;
145
+ opacity: 0;
146
+ transition: opacity 0.2s;
147
+ margin-bottom: 2px;
148
+ }
149
+
150
+ .help-tooltip:hover::before {
151
+ opacity: 1;
152
+ }
src/js/fourier_transform.js CHANGED
@@ -202,20 +202,19 @@ function generateCompositeSignal() {
202
  const amplitude = parseFloat(document.getElementById(`amp${i}`).value);
203
  const phase = parseInt(document.getElementById(`phase${i}`).value);
204
 
205
- if (amplitude > 0) {
206
- const wave = generateSineWave(frequency, amplitude, phase, SAMPLING_RATE, numSamples);
207
- individualWaves.push({
208
- frequency,
209
- amplitude,
210
- phase,
211
- color: WAVE_COLORS[i - 1],
212
- data: wave
213
- });
214
-
215
- // Add to composite signal
216
- for (let n = 0; n < numSamples; n++) {
217
- signal[n] += wave[n];
218
- }
219
  }
220
  }
221
 
@@ -473,8 +472,12 @@ function updateVisualizations() {
473
  magnitudeChart.options.scales.x.max = maxFreq;
474
 
475
  // Update Phase Spectrum
 
 
 
 
476
  const significantPhases = filteredFreqIndices
477
- .filter(item => magnitudes[item.i] > 0.1) // Only show phase for significant frequencies
478
  .map(item => ({
479
  x: item.f,
480
  y: phases[item.i]
 
202
  const amplitude = parseFloat(document.getElementById(`amp${i}`).value);
203
  const phase = parseInt(document.getElementById(`phase${i}`).value);
204
 
205
+ // Generate wave even if amplitude is 0, as long as the wave is enabled
206
+ const wave = generateSineWave(frequency, amplitude, phase, SAMPLING_RATE, numSamples);
207
+ individualWaves.push({
208
+ frequency,
209
+ amplitude,
210
+ phase,
211
+ color: WAVE_COLORS[i - 1],
212
+ data: wave
213
+ });
214
+
215
+ // Add to composite signal
216
+ for (let n = 0; n < numSamples; n++) {
217
+ signal[n] += wave[n];
 
218
  }
219
  }
220
 
 
472
  magnitudeChart.options.scales.x.max = maxFreq;
473
 
474
  // Update Phase Spectrum
475
+ // Use dynamic threshold based on max magnitude to avoid noise in phase spectrum
476
+ const maxMagnitude = Math.max(...magnitudes);
477
+ const threshold = Math.max(maxMagnitude * 0.01, 0.001); // At least 1% of max or 0.001
478
+
479
  const significantPhases = filteredFreqIndices
480
+ .filter(item => magnitudes[item.i] > threshold) // Only show phase for significant frequencies
481
  .map(item => ({
482
  x: item.f,
483
  y: phases[item.i]