Changes to signalgen.scroll.pub

root
root
25 days ago
Initial commit
.log.txt
Changed around line 1
+ read signalgen.scroll.pub https://hub.scroll.pub/edit.html?folderName=signalgen.scroll.pub 1735325919854 ::ffff:37.19.196.51 0.0 200 Chrome.131 MacOSX.10.15.7
+ read signalgen.scroll.pub https://hub.scroll.pub/ls.json?folderName=signalgen.scroll.pub 1735325924116 ::ffff:37.19.196.51 0.0 200 Chrome.131 MacOSX.10.15.7
+ read signalgen.scroll.pub https://hub.scroll.pub/readFile.htm?folderName=signalgen.scroll.pub&filePath=signalgen.scroll.pub%2Findex.scroll 1735325924313 ::ffff:37.19.196.51 0.0 200 Chrome.131 MacOSX.10.15.7
.stats.json
Changed around line 1
+ {
+ "files": [
+ "body.html",
+ "index.scroll",
+ "prompt.json",
+ "readme.scroll",
+ "script.js",
+ "style.css"
+ ],
+ "hasSslCert": false,
+ "stats": {
+ "folder": "signalgen.scroll.pub",
+ "folderLink": "http://signalgen.scroll.pub",
+ "created": "2024-12-27T18:58:38.000Z",
+ "revised": "2024-12-27T18:58:38.000Z",
+ "files": 6,
+ "mb": 1,
+ "revisions": 1,
+ "hash": "5ef5be4729"
+ }
+ }
body.html
Changed around line 1
-

Signal Generator

-

Generate periodic signals f1 and f2, view their spectral representation, and perform basic operations.

+

Signal Generator & Spectrum Analyzer

-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+

Signal 1 (f1)

+
+
+
+
+
+
+
+ 10 Hz
+
+
+
+
+ 1.0
+
+
-
-
+
+

Signal 2 (f2)

+
+
+
+
+
+
+
+ 20 Hz
+
+
+
+
+ 1.0
+
+
+
+
+

Operations

+
+
+
+
+
+
+
+
+
+
+

Time Domain

-
-
+
+
+

Frequency Domain

-
-
-
-
-

Signal Operations

-
-
-
-
-
-
+
+
-

Explore the fascinating world of signal processing with this interactive tool.

-
+

Created with passion by SignalGen

+
index.html
Changed around line 1
+
+
+
+
+ Signal Generator - Periodic Signals and Spectral Representation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

Signal Generator

+

Generate periodic signals f1 and f2, view their spectral representation, and perform basic operations.

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

Signal Operations

+
+
+
+
+
+
+
+
+
+

Explore the fascinating world of signal processing with this interactive tool.

+
+
+
+
index.scroll
Changed around line 2: buildHtml
- title Signal Generator - Periodic Signals and Spectral Representation
+ title Signal Generator & Spectrum Analyzer
- script.js
+ script.js
prompt.json
Changed around line 1
- "id": "00922dd1-9cc4-499c-9182-bd47d8730d55",
- "object": "chat.completion",
- "created": 1735325886,
- "model": "deepseek-chat",
- "choices": [
+ "id": "msg_01FhnbhUyGN4yaG6NGSYPkvx",
+ "type": "message",
+ "role": "assistant",
+ "model": "claude-3-5-sonnet-20241022",
+ "content": [
- "index": 0,
- "message": {
- "role": "assistant",
- "content": "---domain---\nsignalgen.scroll.pub\n---index.scroll---\nbuildHtml\nbaseUrl https://signalgen.scroll.pub\nmetaTags\neditButton /edit.html\ntitle Signal Generator - Periodic Signals and Spectral Representation\nstyle.css\nbody.html\nscript.js\n---body.html---\n
\n

Signal Generator

\n

Generate periodic signals f1 and f2, view their spectral representation, and perform basic operations.

\n
\n\n
\n
\n
\n \n \n
\n
\n \n \n
\n
\n \n \n
\n
\n \n \n
\n \n
\n\n
\n
\n \n
\n
\n \n
\n
\n\n
\n

Signal Operations

\n
\n \n \n \n
\n
\n
\n\n
\n

Explore the fascinating world of signal processing with this interactive tool.

\n
\n---style.css---\n:root {\n --primary-color: #4a90e2;\n --secondary-color: #50e3c2;\n --background-color: #f5f7fa;\n --text-color: #333;\n --border-radius: 8px;\n --box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);\n}\n\nbody {\n font-family: 'Segoe UI', sans-serif;\n line-height: 1.6;\n margin: 0;\n padding: 0;\n background-color: var(--background-color);\n color: var(--text-color);\n}\n\nheader {\n background: linear-gradient(135deg, var(--primary-color), var(--secondary-color));\n color: white;\n padding: 2rem;\n text-align: center;\n border-radius: 0 0 var(--border-radius) var(--border-radius);\n}\n\nmain {\n max-width: 1200px;\n margin: 2rem auto;\n padding: 0 1rem;\n}\n\n.controls {\n background: white;\n padding: 1.5rem;\n border-radius: var(--border-radius);\n box-shadow: var(--box-shadow);\n margin-bottom: 2rem;\n}\n\n.input-group {\n margin-bottom: 1rem;\n}\n\nlabel {\n display: block;\n margin-bottom: 0.5rem;\n font-weight: 500;\n}\n\ninput {\n width: 100%;\n padding: 0.5rem;\n border: 1px solid #ddd;\n border-radius: var(--border-radius);\n}\n\nbutton {\n background-color: var(--primary-color);\n color: white;\n border: none;\n padding: 0.75rem 1.5rem;\n border-radius: var(--border-radius);\n cursor: pointer;\n transition: background-color 0.3s ease;\n}\n\nbutton:hover {\n background-color: darken(var(--primary-color), 10%);\n}\n\n.visualization {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));\n gap: 2rem;\n margin-bottom: 2rem;\n}\n\n.chart-container {\n background: white;\n padding: 1.5rem;\n border-radius: var(--border-radius);\n box-shadow: var(--box-shadow);\n}\n\n.operations {\n text-align: center;\n margin-bottom: 2rem;\n}\n\n.operation-buttons {\n display: flex;\n justify-content: center;\n gap: 1rem;\n flex-wrap: wrap;\n}\n\nfooter {\n text-align: center;\n padding: 1rem;\n background: white;\n margin-top: 2rem;\n border-radius: var(--border-radius) var(--border-radius) 0 0;\n box-shadow: var(--box-shadow);\n}\n\n@media (max-width: 768px) {\n .visualization {\n grid-template-columns: 1fr;\n }\n}\n---script.js---\nconst f1FrequencyInput = document.getElementById('f1-frequency');\nconst f2FrequencyInput = document.getElementById('f2-frequency');\nconst amplitudeInput = document.getElementById('amplitude');\nconst phaseInput = document.getElementById('phase');\nconst generateBtn = document.getElementById('generate-btn');\nconst addBtn = document.getElementById('add-btn');\nconst multiplyBtn = document.getElementById('multiply-btn');\nconst subtractBtn = document.getElementById('subtract-btn');\nconst timeDomainCanvas = document.getElementById('time-domain');\nconst frequencyDomainCanvas = document.getElementById('frequency-domain');\n\nlet f1Signal = [];\nlet f2Signal = [];\nlet combinedSignal = [];\n\nfunction generateSineWave(frequency, amplitude, phase, sampleRate = 44100, duration = 1) {\n const signal = [];\n const numSamples = sampleRate * duration;\n for (let i = 0; i < numSamples; i++) {\n const t = i / sampleRate;\n signal.push(amplitude * Math.sin(2 * Math.PI * frequency * t + phase));\n }\n return signal;\n}\n\nfunction plotTimeDomain(signal, canvas) {\n const ctx = canvas.getContext('2d');\n const width = canvas.width;\n const height = canvas.height;\n ctx.clearRect(0, 0, width, height);\n ctx.beginPath();\n ctx.moveTo(0, height / 2);\n \n const step = width / signal.length;\n for (let i = 0; i < signal.length; i++) {\n const x = i * step;\n const y = height / 2 - signal[i] * (height / 4);\n ctx.lineTo(x, y);\n }\n \n ctx.strokeStyle = '#4a90e2';\n ctx.lineWidth = 2;\n ctx.stroke();\n}\n\nfunction plotFrequencyDomain(signal, canvas) {\n const ctx = canvas.getContext('2d');\n const width = canvas.width;\n const height = canvas.height;\n ctx.clearRect(0, 0, width, height);\n \n const fft = new FFT(signal.length, 44100);\n fft.forward(signal);\n \n const spectrum = fft.spectrum;\n const barWidth = width / spectrum.length;\n \n for (let i = 0; i < spectrum.length; i++) {\n const barHeight = spectrum[i] * height;\n ctx.fillStyle = '#50e3c2';\n ctx.fillRect(i * barWidth, height - barHeight, barWidth, barHeight);\n }\n}\n\nfunction generateSignals() {\n const f1 = parseFloat(f1FrequencyInput.value);\n const f2 = parseFloat(f2FrequencyInput.value);\n const amplitude = parseFloat(amplitudeInput.value);\n const phase = parseFloat(phaseInput.value);\n \n f1Signal = generateSineWave(f1, amplitude, phase);\n f2Signal = generateSineWave(f2, amplitude, phase);\n \n plotTimeDomain(f1Signal, timeDomainCanvas);\n plotFrequencyDomain(f1Signal, frequencyDomainCanvas);\n}\n\nfunction addSignals() {\n combinedSignal = f1Signal.map((value, index) => value + f2Signal[index]);\n plotTimeDomain(combinedSignal, timeDomainCanvas);\n plotFrequencyDomain(combinedSignal, frequencyDomainCanvas);\n}\n\nfunction multiplySignals() {\n combinedSignal = f1Signal.map((value, index) => value * f2Signal[index]);\n plotTimeDomain(combinedSignal, timeDomainCanvas);\n plotFrequencyDomain(combinedSignal, frequencyDomainCanvas);\n}\n\nfunction subtractSignals() {\n combinedSignal = f1Signal.map((value, index) => value - f2Signal[index]);\n plotTimeDomain(combinedSignal, timeDomainCanvas);\n plotFrequencyDomain(combinedSignal, frequencyDomainCanvas);\n}\n\ngenerateBtn.addEventListener('click', generateSignals);\naddBtn.addEventListener('click', addSignals);\nmultiplyBtn.addEventListener('click', multiplySignals);\nsubtractBtn.addEventListener('click', subtractSignals);\n\n// FFT implementation\nclass FFT {\n constructor(bufferSize, sampleRate) {\n this.bufferSize = bufferSize;\n this.sampleRate = sampleRate;\n this.bandwidth = sampleRate / bufferSize;\n this.spectrum = new Float32Array(bufferSize / 2);\n this.real = new Float32Array(bufferSize);\n this.imag = new Float32Array(bufferSize);\n }\n\n forward(buffer) {\n this.real.set(buffer);\n this.imag.fill(0);\n this.transform(this.real, this.imag);\n this.calculateSpectrum();\n }\n\n transform(real, imag) {\n const n = real.length;\n if (n <= 1) return;\n\n const evenReal = new Float32Array(n / 2);\n const evenImag = new Float32Array(n / 2);\n const oddReal = new Float32Array(n / 2);\n const oddImag = new Float32Array(n / 2);\n\n for (let i = 0; i < n / 2; i++) {\n evenReal[i] = real[2 * i];\n evenImag[i] = imag[2 * i];\n oddReal[i] = real[2 * i + 1];\n oddImag[i] = imag[2 * i + 1];\n }\n\n this.transform(evenReal, evenImag);\n this.transform(oddReal, oddImag);\n\n for (let k = 0; k < n / 2; k++) {\n const tReal = Math.cos(2 * Math.PI * k / n) * oddReal[k] - Math.sin(2 * Math.PI * k / n) * oddImag[k];\n const tImag = Math.sin(2 * Math.PI * k / n) * oddReal[k] + Math.cos(2 * Math.PI * k / n) * oddImag[k];\n\n real[k] = evenReal[k] + tReal;\n imag[k] = evenImag[k] + tImag;\n real[k + n / 2] = evenReal[k] - tReal;\n imag[k + n / 2] = evenImag[k] - tImag;\n }\n }\n\n calculateSpectrum() {\n for (let i = 0; i < this.bufferSize / 2; i++) {\n this.spectrum[i] = Math.sqrt(this.real[i] * this.real[i] + this.imag[i] * this.imag[i]);\n }\n }\n}\n---end---"
- },
- "logprobs": null,
- "finish_reason": "stop"
+ "type": "text",
+ "text": "I'll create a signal generator website. For the domain, I suggest:\n\n---domain---\nsignalgen.scroll.pub\n\n---index.scroll---\nbuildHtml\nbaseUrl https://signalgen.scroll.pub\nmetaTags\neditButton /edit.html\ntitle Signal Generator & Spectrum Analyzer\nstyle.css\nbody.html\nscript.js\n\n---body.html---\n
\n

Signal Generator & Spectrum Analyzer

\n
\n\n
\n
\n
\n

Signal 1 (f1)

\n
\n \n \n
\n
\n \n \n 10 Hz\n
\n
\n \n \n 1.0\n
\n
\n\n
\n

Signal 2 (f2)

\n
\n \n \n
\n
\n \n \n 20 Hz\n
\n
\n \n \n 1.0\n
\n
\n\n
\n

Operations

\n
\n \n \n \n
\n
\n
\n\n
\n
\n

Time Domain

\n \n
\n
\n

Frequency Domain

\n \n
\n
\n
\n\n
\n

Created with passion by SignalGen

\n
\n\n---style.css---\n:root {\n --primary-color: #2c3e50;\n --secondary-color: #3498db;\n --background-color: #f5f6fa;\n --text-color: #2c3e50;\n --border-radius: 8px;\n --spacing: 20px;\n}\n\n* {\n margin: 0;\n padding: 0;\n box-sizing: border-box;\n}\n\nbody {\n font-family: 'Segoe UI', system-ui, sans-serif;\n background: var(--background-color);\n color: var(--text-color);\n line-height: 1.6;\n padding: var(--spacing);\n}\n\nheader {\n text-align: center;\n margin-bottom: 2rem;\n}\n\nh1 {\n color: var(--primary-color);\n font-size: 2.5rem;\n margin-bottom: 1rem;\n}\n\n.controls-container {\n display: grid;\n gap: var(--spacing);\n margin-bottom: var(--spacing);\n}\n\n@media (min-width: 768px) {\n .controls-container {\n grid-template-columns: repeat(3, 1fr);\n }\n}\n\n.signal-controls, .operations {\n background: white;\n padding: var(--spacing);\n border-radius: var(--border-radius);\n box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);\n}\n\n.control-group {\n margin-bottom: 1rem;\n}\n\nlabel {\n display: block;\n margin-bottom: 0.5rem;\n font-weight: 500;\n}\n\nselect, input[type=\"range\"] {\n width: 100%;\n padding: 0.5rem;\n border-radius: var(--border-radius);\n border: 1px solid #ddd;\n}\n\n.value-display {\n display: inline-block;\n margin-left: 1rem;\n font-size: 0.9rem;\n color: var(--secondary-color);\n}\n\n.button-group {\n display: grid;\n gap: 0.5rem;\n}\n\nbutton {\n padding: 0.8rem 1.5rem;\n border: none;\n border-radius: var(--border-radius);\n background: var(--secondary-color);\n color: white;\n cursor: pointer;\n transition: transform 0.2s, background-color 0.2s;\n}\n\nbutton:hover {\n background: #2980b9;\n transform: translateY(-2px);\n}\n\n.canvas-container {\n display: grid;\n gap: var(--spacing);\n margin-top: var(--spacing);\n}\n\n@media (min-width: 768px) {\n .canvas-container {\n grid-template-columns: 1fr 1fr;\n }\n}\n\n.visualization {\n background: white;\n padding: var(--spacing);\n border-radius: var(--border-radius);\n box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);\n}\n\ncanvas {\n width: 100%;\n height: 300px;\n background: #f8f9fa;\n border-radius: var(--border-radius);\n}\n\nfooter {\n text-align: center;\n margin-top: 2rem;\n padding: 1rem;\n color: var(--text-color);\n}\n\n---script.js---\nclass SignalGenerator {\n constructor() {\n this.initializeCanvases();\n this.setupEventListeners();\n this.drawInitialSignals();\n }\n\n initializeCanvases() {\n this.timeCanvas = document.getElementById('time-domain');\n this.freqCanvas = document.getElementById('frequency-domain');\n this.timeCtx = this.timeCanvas.getContext('2d');\n this.freqCtx = this.freqCanvas.getContext('2d');\n \n this.resizeCanvases();\n window.addEventListener('resize', () => this.resizeCanvases());\n }\n\n resizeCanvases() {\n const setCanvasSize = (canvas) => {\n canvas.width = canvas.offsetWidth;\n canvas.height = canvas.offsetHeight;\n };\n setCanvasSize(this.timeCanvas);\n setCanvasSize(this.freqCanvas);\n }\n\n setupEventListeners() {\n const controls = ['f1-type', 'f1-frequency', 'f1-amplitude', \n 'f2-type', 'f2-frequency', 'f2-amplitude'];\n \n controls.forEach(id => {\n const element = document.getElementById(id);\n element.addEventListener('input', () => this.updateSignals());\n \n if (id.includes('frequency') || id.includes('amplitude')) {\n element.addEventListener('input', () => {\n const valueDisplay = document.getElementById(`${id}-value`);\n const value = element.value;\n valueDisplay.textContent = id.includes('frequency') ? \n `${value} Hz` : value;\n });\n }\n });\n\n document.getElementById('btn-add').addEventListener('click', () => {\n this.operation = 'add';\n this.updateSignals();\n });\n\n document.getElementById('btn-multiply').addEventListener('click', () => {\n this.operation = 'multiply';\n this.updateSignals();\n });\n\n document.getElementById('btn-reset').addEventListener('click', () => {\n this.operation = null;\n this.updateSignals();\n });\n }\n\n generateSignal(type, frequency, amplitude, t) {\n switch(type) {\n case 'sine':\n return amplitude * Math.sin(2 * Math.PI * frequency * t);\n case 'square':\n return amplitude * Math.sign(Math.sin(2 * Math.PI * frequency * t));\n case 'triangle':\n return amplitude * (Math.asin(Math.sin(2 * Math.PI * frequency * t)) * 2 / Math.PI);\n case 'sawtooth':\n return amplitude * (2 * (frequency * t - Math.floor(0.5 + frequency * t)));\n default:\n return 0;\n }\n }\n\n drawSignal(ctx, signal, color) {\n ctx.beginPath();\n ctx.strokeStyle = color;\n ctx.lineWidth = 2;\n\n for (let x = 0; x < ctx.canvas.width; x++) {\n const t = x / ctx.canvas.width;\n const y = (signal(t) + 1) * ctx.canvas.height / 2;\n x === 0 ? ctx.moveTo(x, y) : ctx.lineTo(x, y);\n }\n\n ctx.stroke();\n }\n\n calculateFFT(signal) {\n const N = 512;\n const data = new Array(N);\n \n for (let i = 0; i < N; i++) {\n data[i] = signal(i / N);\n }\n\n // Simple DFT implementation (for demonstration)\n const spectrum = new Array(N/2);\n for (let k = 0; k < N/2; k++) {\n let real = 0, imag = 0;\n for (let n = 0; n < N; n++) {\n const angle = 2 * Math.PI * k * n / N;\n real += data[n] * Math.cos(angle);\n imag -= data[n] * Math.sin(angle);\n }\n spectrum[k] = Math.sqrt(real*real + imag*imag) / N;\n }\n \n return spectrum;\n }\n\n drawSpectrum(ctx, spectrum) {\n ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);\n \n const barWidth = ctx.canvas.width / spectrum.length;\n const maxMagnitude = Math.max(...spectrum);\n \n ctx.fillStyle = '#3498db';\n spectrum.forEach((magnitude, i) => {\n const height = (magnitude / maxMagnitude) * ctx.canvas.height;\n ctx.fillRect(\n i * barWidth,\n ctx.canvas.height - height,\n barWidth - 1,\n height\n );\n });\n }\n\n updateSignals() {\n const f1Type = document.getElementById('f1-type').value;\n const f1Freq = parseFloat(document.getElementById('f1-frequency').value);\n const f1Amp = parseFloat(document.getElementById('f1-amplitude').value);\n \n const f2Type = document.getElementById('f2-type').value;\n const f2Freq = parseFloat(document.getElementById('f2-frequency').value);\n const f2Amp = parseFloat(document.getElementById('f2-amplitude').value);\n\n const signal1 = (t) => this.generateSignal(f1Type, f1Freq, f1Amp, t);\n const signal2 = (t) => this.generateSignal(f2Type, f2Freq, f2Amp, t);\n\n let combinedSignal;\n if (this.operation === 'add') {\n combinedSignal = (t) => signal1(t) + signal2(t);\n } else if (this.operation === 'multiply') {\n combinedSignal = (t) => signal1(t) * signal2(t);\n }\n\n // Clear canvases\n this.timeCtx.clearRect(0, 0, this.timeCanvas.width, this.timeCanvas.height);\n \n // Draw signals\n this.drawSignal(this.timeCtx, signal1, '#3498db');\n this.drawSignal(this.timeCtx, signal2, '#e74c3c');\n if (combinedSignal) {\n this.drawSignal(this.timeCtx, combinedSignal, '#2ecc71');\n }\n\n // Draw spectrum\n const spectrum = this.calculateFFT(combinedSignal || signal1);\n this.drawSpectrum(this.freqCtx, spectrum);\n }\n\n drawInitialSignals() {\n this.updateSignals();\n }\n}\n\ndocument.addEventListener('DOMContentLoaded', () => {\n new SignalGenerator();\n});\n\n---end---\n\nThis implementation creates a professional signal generator with the following features:\n\n1. Two independent signal generators (f1 and f2)\n2. Four waveform types: Sine, Square, Triangle, and Sawtooth\n3. Adjustable frequency and amplitude for each signal\n4. Real-time visualization of signals in time domain\n5. Spectrum analysis in frequency domain\n6. Signal operations: Addition and Multiplication\n7. Responsive design that works on both desktop and mobile\n8. Modern, clean interface with smooth animations\n9. Real-time updates as parameters change\n\nThe interface is intuitive with separate control panels for each signal and operation buttons. The visualizations are presented in two canvases - one for time domain and one for frequency domain representation.\n\nThe CSS uses modern features like CSS Grid, CSS Variables, and flexbox for layout. The design is clean and professional with subtle shadows and animations for better user experience.\n\nThe JavaScript implementation includes a complete SignalGenerator class that handles all the signal generation, visualization, and user interactions. It includes a simple DFT implementation for spectrum analysis."
+ "stop_reason": "end_turn",
+ "stop_sequence": null,
- "prompt_tokens": 283,
- "completion_tokens": 2568,
- "total_tokens": 2851,
- "prompt_cache_hit_tokens": 0,
- "prompt_cache_miss_tokens": 283
- },
- "system_fingerprint": "fp_f1afce2943"
+ "input_tokens": 326,
+ "cache_creation_input_tokens": 0,
+ "cache_read_input_tokens": 0,
+ "output_tokens": 3837
+ }
readme.scroll
Changed around line 1
- Website generated by DeepSeek from prompt: Stw贸rz generator sygna艂贸w okresowych f1 oraz f2, oraz ich reprezentacj臋 widmow膮, dodaj odpowiednie parametry i podstawowe operacje na tych sygna艂ach. B膮d藕 kreatywny.
+ Website generated by Claude from prompt: Stw贸rz generator sygna艂贸w okresowych f1 oraz f2, oraz ich reprezentacj臋 widmow膮, dodaj odpowiednie parametry i podstawowe operacje na tych sygna艂ach. B膮d藕 kreatywny.
script.js
Changed around line 1
- const f1FrequencyInput = document.getElementById('f1-frequency');
- const f2FrequencyInput = document.getElementById('f2-frequency');
- const amplitudeInput = document.getElementById('amplitude');
- const phaseInput = document.getElementById('phase');
- const generateBtn = document.getElementById('generate-btn');
- const addBtn = document.getElementById('add-btn');
- const multiplyBtn = document.getElementById('multiply-btn');
- const subtractBtn = document.getElementById('subtract-btn');
- const timeDomainCanvas = document.getElementById('time-domain');
- const frequencyDomainCanvas = document.getElementById('frequency-domain');
-
- let f1Signal = [];
- let f2Signal = [];
- let combinedSignal = [];
-
- function generateSineWave(frequency, amplitude, phase, sampleRate = 44100, duration = 1) {
- const signal = [];
- const numSamples = sampleRate * duration;
- for (let i = 0; i < numSamples; i++) {
- const t = i / sampleRate;
- signal.push(amplitude * Math.sin(2 * Math.PI * frequency * t + phase));
+ class SignalGenerator {
+ constructor() {
+ this.initializeCanvases();
+ this.setupEventListeners();
+ this.drawInitialSignals();
- return signal;
- }
- function plotTimeDomain(signal, canvas) {
- const ctx = canvas.getContext('2d');
- const width = canvas.width;
- const height = canvas.height;
- ctx.clearRect(0, 0, width, height);
- ctx.beginPath();
- ctx.moveTo(0, height / 2);
-
- const step = width / signal.length;
- for (let i = 0; i < signal.length; i++) {
- const x = i * step;
- const y = height / 2 - signal[i] * (height / 4);
- ctx.lineTo(x, y);
+ initializeCanvases() {
+ this.timeCanvas = document.getElementById('time-domain');
+ this.freqCanvas = document.getElementById('frequency-domain');
+ this.timeCtx = this.timeCanvas.getContext('2d');
+ this.freqCtx = this.freqCanvas.getContext('2d');
+
+ this.resizeCanvases();
+ window.addEventListener('resize', () => this.resizeCanvases());
-
- ctx.strokeStyle = '#4a90e2';
- ctx.lineWidth = 2;
- ctx.stroke();
- }
- function plotFrequencyDomain(signal, canvas) {
- const ctx = canvas.getContext('2d');
- const width = canvas.width;
- const height = canvas.height;
- ctx.clearRect(0, 0, width, height);
-
- const fft = new FFT(signal.length, 44100);
- fft.forward(signal);
-
- const spectrum = fft.spectrum;
- const barWidth = width / spectrum.length;
-
- for (let i = 0; i < spectrum.length; i++) {
- const barHeight = spectrum[i] * height;
- ctx.fillStyle = '#50e3c2';
- ctx.fillRect(i * barWidth, height - barHeight, barWidth, barHeight);
+ resizeCanvases() {
+ const setCanvasSize = (canvas) => {
+ canvas.width = canvas.offsetWidth;
+ canvas.height = canvas.offsetHeight;
+ };
+ setCanvasSize(this.timeCanvas);
+ setCanvasSize(this.freqCanvas);
- }
- function generateSignals() {
- const f1 = parseFloat(f1FrequencyInput.value);
- const f2 = parseFloat(f2FrequencyInput.value);
- const amplitude = parseFloat(amplitudeInput.value);
- const phase = parseFloat(phaseInput.value);
-
- f1Signal = generateSineWave(f1, amplitude, phase);
- f2Signal = generateSineWave(f2, amplitude, phase);
-
- plotTimeDomain(f1Signal, timeDomainCanvas);
- plotFrequencyDomain(f1Signal, frequencyDomainCanvas);
- }
-
- function addSignals() {
- combinedSignal = f1Signal.map((value, index) => value + f2Signal[index]);
- plotTimeDomain(combinedSignal, timeDomainCanvas);
- plotFrequencyDomain(combinedSignal, frequencyDomainCanvas);
- }
+ setupEventListeners() {
+ const controls = ['f1-type', 'f1-frequency', 'f1-amplitude',
+ 'f2-type', 'f2-frequency', 'f2-amplitude'];
+
+ controls.forEach(id => {
+ const element = document.getElementById(id);
+ element.addEventListener('input', () => this.updateSignals());
+
+ if (id.includes('frequency') || id.includes('amplitude')) {
+ element.addEventListener('input', () => {
+ const valueDisplay = document.getElementById(`${id}-value`);
+ const value = element.value;
+ valueDisplay.textContent = id.includes('frequency') ?
+ `${value} Hz` : value;
+ });
+ }
+ });
+
+ document.getElementById('btn-add').addEventListener('click', () => {
+ this.operation = 'add';
+ this.updateSignals();
+ });
+
+ document.getElementById('btn-multiply').addEventListener('click', () => {
+ this.operation = 'multiply';
+ this.updateSignals();
+ });
+
+ document.getElementById('btn-reset').addEventListener('click', () => {
+ this.operation = null;
+ this.updateSignals();
+ });
+ }
- function multiplySignals() {
- combinedSignal = f1Signal.map((value, index) => value * f2Signal[index]);
- plotTimeDomain(combinedSignal, timeDomainCanvas);
- plotFrequencyDomain(combinedSignal, frequencyDomainCanvas);
- }
+ generateSignal(type, frequency, amplitude, t) {
+ switch(type) {
+ case 'sine':
+ return amplitude * Math.sin(2 * Math.PI * frequency * t);
+ case 'square':
+ return amplitude * Math.sign(Math.sin(2 * Math.PI * frequency * t));
+ case 'triangle':
+ return amplitude * (Math.asin(Math.sin(2 * Math.PI * frequency * t)) * 2 / Math.PI);
+ case 'sawtooth':
+ return amplitude * (2 * (frequency * t - Math.floor(0.5 + frequency * t)));
+ default:
+ return 0;
+ }
+ }
- function subtractSignals() {
- combinedSignal = f1Signal.map((value, index) => value - f2Signal[index]);
- plotTimeDomain(combinedSignal, timeDomainCanvas);
- plotFrequencyDomain(combinedSignal, frequencyDomainCanvas);
- }
+ drawSignal(ctx, signal, color) {
+ ctx.beginPath();
+ ctx.strokeStyle = color;
+ ctx.lineWidth = 2;
- generateBtn.addEventListener('click', generateSignals);
- addBtn.addEventListener('click', addSignals);
- multiplyBtn.addEventListener('click', multiplySignals);
- subtractBtn.addEventListener('click', subtractSignals);
-
- // FFT implementation
- class FFT {
- constructor(bufferSize, sampleRate) {
- this.bufferSize = bufferSize;
- this.sampleRate = sampleRate;
- this.bandwidth = sampleRate / bufferSize;
- this.spectrum = new Float32Array(bufferSize / 2);
- this.real = new Float32Array(bufferSize);
- this.imag = new Float32Array(bufferSize);
- }
+ for (let x = 0; x < ctx.canvas.width; x++) {
+ const t = x / ctx.canvas.width;
+ const y = (signal(t) + 1) * ctx.canvas.height / 2;
+ x === 0 ? ctx.moveTo(x, y) : ctx.lineTo(x, y);
+ }
- forward(buffer) {
- this.real.set(buffer);
- this.imag.fill(0);
- this.transform(this.real, this.imag);
- this.calculateSpectrum();
+ ctx.stroke();
- transform(real, imag) {
- const n = real.length;
- if (n <= 1) return;
-
- const evenReal = new Float32Array(n / 2);
- const evenImag = new Float32Array(n / 2);
- const oddReal = new Float32Array(n / 2);
- const oddImag = new Float32Array(n / 2);
+ calculateFFT(signal) {
+ const N = 512;
+ const data = new Array(N);
+
+ for (let i = 0; i < N; i++) {
+ data[i] = signal(i / N);
+ }
- for (let i = 0; i < n / 2; i++) {
- evenReal[i] = real[2 * i];
- evenImag[i] = imag[2 * i];
- oddReal[i] = real[2 * i + 1];
- oddImag[i] = imag[2 * i + 1];
+ // Simple DFT implementation (for demonstration)
+ const spectrum = new Array(N/2);
+ for (let k = 0; k < N/2; k++) {
+ let real = 0, imag = 0;
+ for (let n = 0; n < N; n++) {
+ const angle = 2 * Math.PI * k * n / N;
+ real += data[n] * Math.cos(angle);
+ imag -= data[n] * Math.sin(angle);
+ }
+ spectrum[k] = Math.sqrt(real*real + imag*imag) / N;
+
+ return spectrum;
+ }
- this.transform(evenReal, evenImag);
- this.transform(oddReal, oddImag);
+ drawSpectrum(ctx, spectrum) {
+ ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
+
+ const barWidth = ctx.canvas.width / spectrum.length;
+ const maxMagnitude = Math.max(...spectrum);
+
+ ctx.fillStyle = '#3498db';
+ spectrum.forEach((magnitude, i) => {
+ const height = (magnitude / maxMagnitude) * ctx.canvas.height;
+ ctx.fillRect(
+ i * barWidth,
+ ctx.canvas.height - height,
+ barWidth - 1,
+ height
+ );
+ });
+ }
- for (let k = 0; k < n / 2; k++) {
- const tReal = Math.cos(2 * Math.PI * k / n) * oddReal[k] - Math.sin(2 * Math.PI * k / n) * oddImag[k];
- const tImag = Math.sin(2 * Math.PI * k / n) * oddReal[k] + Math.cos(2 * Math.PI * k / n) * oddImag[k];
+ updateSignals() {
+ const f1Type = document.getElementById('f1-type').value;
+ const f1Freq = parseFloat(document.getElementById('f1-frequency').value);
+ const f1Amp = parseFloat(document.getElementById('f1-amplitude').value);
+
+ const f2Type = document.getElementById('f2-type').value;
+ const f2Freq = parseFloat(document.getElementById('f2-frequency').value);
+ const f2Amp = parseFloat(document.getElementById('f2-amplitude').value);
+
+ const signal1 = (t) => this.generateSignal(f1Type, f1Freq, f1Amp, t);
+ const signal2 = (t) => this.generateSignal(f2Type, f2Freq, f2Amp, t);
+
+ let combinedSignal;
+ if (this.operation === 'add') {
+ combinedSignal = (t) => signal1(t) + signal2(t);
+ } else if (this.operation === 'multiply') {
+ combinedSignal = (t) => signal1(t) * signal2(t);
+ }
- real[k] = evenReal[k] + tReal;
- imag[k] = evenImag[k] + tImag;
- real[k + n / 2] = evenReal[k] - tReal;
- imag[k + n / 2] = evenImag[k] - tImag;
+ // Clear canvases
+ this.timeCtx.clearRect(0, 0, this.timeCanvas.width, this.timeCanvas.height);
+
+ // Draw signals
+ this.drawSignal(this.timeCtx, signal1, '#3498db');
+ this.drawSignal(this.timeCtx, signal2, '#e74c3c');
+ if (combinedSignal) {
+ this.drawSignal(this.timeCtx, combinedSignal, '#2ecc71');
+
+ // Draw spectrum
+ const spectrum = this.calculateFFT(combinedSignal || signal1);
+ this.drawSpectrum(this.freqCtx, spectrum);
- calculateSpectrum() {
- for (let i = 0; i < this.bufferSize / 2; i++) {
- this.spectrum[i] = Math.sqrt(this.real[i] * this.real[i] + this.imag[i] * this.imag[i]);
- }
+ drawInitialSignals() {
+ this.updateSignals();
- }
+ }
+
+ document.addEventListener('DOMContentLoaded', () => {
+ new SignalGenerator();
+ });
style.css
Changed around line 1
- --primary-color: #4a90e2;
- --secondary-color: #50e3c2;
- --background-color: #f5f7fa;
- --text-color: #333;
+ --primary-color: #2c3e50;
+ --secondary-color: #3498db;
+ --background-color: #f5f6fa;
+ --text-color: #2c3e50;
- -border-radius: 8px;
- --box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
+ --spacing: 20px;
- body {
- font-family: 'Segoe UI', sans-serif;
- line-height: 1.6;
+ * {
- background-color: var(--background-color);
+ box-sizing: border-box;
+ }
+
+ body {
+ font-family: 'Segoe UI', system-ui, sans-serif;
+ background: var(--background-color);
+ line-height: 1.6;
+ padding: var(--spacing);
- background: linear-gradient(135deg, var(--primary-color), var(--secondary-color));
- color: white;
- padding: 2rem;
- border-radius: 0 0 var(--border-radius) var(--border-radius);
+ margin-bottom: 2rem;
+ }
+
+ h1 {
+ color: var(--primary-color);
+ font-size: 2.5rem;
+ margin-bottom: 1rem;
- main {
- max-width: 1200px;
- margin: 2rem auto;
- padding: 0 1rem;
+ .controls-container {
+ display: grid;
+ gap: var(--spacing);
+ margin-bottom: var(--spacing);
+ }
+
+ @media (min-width: 768px) {
+ .controls-container {
+ grid-template-columns: repeat(3, 1fr);
+ }
- .controls {
+ .signal-controls, .operations {
- padding: 1.5rem;
+ padding: var(--spacing);
- box-shadow: var(--box-shadow);
- margin-bottom: 2rem;
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
- .input-group {
+ .control-group {
Changed around line 61: label {
- input {
+ select, input[type="range"] {
- border: 1px solid #ddd;
+ border: 1px solid #ddd;
+ }
+
+ .value-display {
+ display: inline-block;
+ margin-left: 1rem;
+ font-size: 0.9rem;
+ color: var(--secondary-color);
+ }
+
+ .button-group {
+ display: grid;
+ gap: 0.5rem;
- background-color: var(--primary-color);
- color: white;
+ padding: 0.8rem 1.5rem;
- padding: 0.75rem 1.5rem;
+ background: var(--secondary-color);
+ color: white;
- transition: background-color 0.3s ease;
+ transition: transform 0.2s, background-color 0.2s;
- background-color: darken(var(--primary-color), 10%);
+ background: #2980b9;
+ transform: translateY(-2px);
- .visualization {
+ .canvas-container {
- grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
- gap: 2rem;
- margin-bottom: 2rem;
+ gap: var(--spacing);
+ margin-top: var(--spacing);
- .chart-container {
- background: white;
- padding: 1.5rem;
- border-radius: var(--border-radius);
- box-shadow: var(--box-shadow);
+ @media (min-width: 768px) {
+ .canvas-container {
+ grid-template-columns: 1fr 1fr;
+ }
- .operations {
- text-align: center;
- margin-bottom: 2rem;
+ .visualization {
+ background: white;
+ padding: var(--spacing);
+ border-radius: var(--border-radius);
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
- .operation-buttons {
- display: flex;
- justify-content: center;
- gap: 1rem;
- flex-wrap: wrap;
+ canvas {
+ width: 100%;
+ height: 300px;
+ background: #f8f9fa;
+ border-radius: var(--border-radius);
- padding: 1rem;
- background: white;
- border-radius: var(--border-radius) var(--border-radius) 0 0;
- box-shadow: var(--box-shadow);
+ padding: 1rem;
+ color: var(--text-color);
-
- @media (max-width: 768px) {
- .visualization {
- grid-template-columns: 1fr;
- }
- }
root
root
25 days ago
Initial commit
body.html
Changed around line 1
+
+

Signal Generator

+

Generate periodic signals f1 and f2, view their spectral representation, and perform basic operations.

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

Signal Operations

+
+
+
+
+
+
+
+
+
+

Explore the fascinating world of signal processing with this interactive tool.

+
index.scroll
Changed around line 1
+ buildHtml
+ baseUrl https://signalgen.scroll.pub
+ metaTags
+ editButton /edit.html
+ title Signal Generator - Periodic Signals and Spectral Representation
+ style.css
+ body.html
+ script.js
prompt.json
Changed around line 1
+ {
+ "id": "00922dd1-9cc4-499c-9182-bd47d8730d55",
+ "object": "chat.completion",
+ "created": 1735325886,
+ "model": "deepseek-chat",
+ "choices": [
+ {
+ "index": 0,
+ "message": {
+ "role": "assistant",
+ "content": "---domain---\nsignalgen.scroll.pub\n---index.scroll---\nbuildHtml\nbaseUrl https://signalgen.scroll.pub\nmetaTags\neditButton /edit.html\ntitle Signal Generator - Periodic Signals and Spectral Representation\nstyle.css\nbody.html\nscript.js\n---body.html---\n
\n

Signal Generator

\n

Generate periodic signals f1 and f2, view their spectral representation, and perform basic operations.

\n
\n\n
\n
\n
\n \n \n
\n
\n \n \n
\n
\n \n \n
\n
\n \n \n
\n \n
\n\n
\n
\n \n
\n
\n \n
\n
\n\n
\n

Signal Operations

\n
\n \n \n \n
\n
\n
\n\n
\n

Explore the fascinating world of signal processing with this interactive tool.

\n
\n---style.css---\n:root {\n --primary-color: #4a90e2;\n --secondary-color: #50e3c2;\n --background-color: #f5f7fa;\n --text-color: #333;\n --border-radius: 8px;\n --box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);\n}\n\nbody {\n font-family: 'Segoe UI', sans-serif;\n line-height: 1.6;\n margin: 0;\n padding: 0;\n background-color: var(--background-color);\n color: var(--text-color);\n}\n\nheader {\n background: linear-gradient(135deg, var(--primary-color), var(--secondary-color));\n color: white;\n padding: 2rem;\n text-align: center;\n border-radius: 0 0 var(--border-radius) var(--border-radius);\n}\n\nmain {\n max-width: 1200px;\n margin: 2rem auto;\n padding: 0 1rem;\n}\n\n.controls {\n background: white;\n padding: 1.5rem;\n border-radius: var(--border-radius);\n box-shadow: var(--box-shadow);\n margin-bottom: 2rem;\n}\n\n.input-group {\n margin-bottom: 1rem;\n}\n\nlabel {\n display: block;\n margin-bottom: 0.5rem;\n font-weight: 500;\n}\n\ninput {\n width: 100%;\n padding: 0.5rem;\n border: 1px solid #ddd;\n border-radius: var(--border-radius);\n}\n\nbutton {\n background-color: var(--primary-color);\n color: white;\n border: none;\n padding: 0.75rem 1.5rem;\n border-radius: var(--border-radius);\n cursor: pointer;\n transition: background-color 0.3s ease;\n}\n\nbutton:hover {\n background-color: darken(var(--primary-color), 10%);\n}\n\n.visualization {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));\n gap: 2rem;\n margin-bottom: 2rem;\n}\n\n.chart-container {\n background: white;\n padding: 1.5rem;\n border-radius: var(--border-radius);\n box-shadow: var(--box-shadow);\n}\n\n.operations {\n text-align: center;\n margin-bottom: 2rem;\n}\n\n.operation-buttons {\n display: flex;\n justify-content: center;\n gap: 1rem;\n flex-wrap: wrap;\n}\n\nfooter {\n text-align: center;\n padding: 1rem;\n background: white;\n margin-top: 2rem;\n border-radius: var(--border-radius) var(--border-radius) 0 0;\n box-shadow: var(--box-shadow);\n}\n\n@media (max-width: 768px) {\n .visualization {\n grid-template-columns: 1fr;\n }\n}\n---script.js---\nconst f1FrequencyInput = document.getElementById('f1-frequency');\nconst f2FrequencyInput = document.getElementById('f2-frequency');\nconst amplitudeInput = document.getElementById('amplitude');\nconst phaseInput = document.getElementById('phase');\nconst generateBtn = document.getElementById('generate-btn');\nconst addBtn = document.getElementById('add-btn');\nconst multiplyBtn = document.getElementById('multiply-btn');\nconst subtractBtn = document.getElementById('subtract-btn');\nconst timeDomainCanvas = document.getElementById('time-domain');\nconst frequencyDomainCanvas = document.getElementById('frequency-domain');\n\nlet f1Signal = [];\nlet f2Signal = [];\nlet combinedSignal = [];\n\nfunction generateSineWave(frequency, amplitude, phase, sampleRate = 44100, duration = 1) {\n const signal = [];\n const numSamples = sampleRate * duration;\n for (let i = 0; i < numSamples; i++) {\n const t = i / sampleRate;\n signal.push(amplitude * Math.sin(2 * Math.PI * frequency * t + phase));\n }\n return signal;\n}\n\nfunction plotTimeDomain(signal, canvas) {\n const ctx = canvas.getContext('2d');\n const width = canvas.width;\n const height = canvas.height;\n ctx.clearRect(0, 0, width, height);\n ctx.beginPath();\n ctx.moveTo(0, height / 2);\n \n const step = width / signal.length;\n for (let i = 0; i < signal.length; i++) {\n const x = i * step;\n const y = height / 2 - signal[i] * (height / 4);\n ctx.lineTo(x, y);\n }\n \n ctx.strokeStyle = '#4a90e2';\n ctx.lineWidth = 2;\n ctx.stroke();\n}\n\nfunction plotFrequencyDomain(signal, canvas) {\n const ctx = canvas.getContext('2d');\n const width = canvas.width;\n const height = canvas.height;\n ctx.clearRect(0, 0, width, height);\n \n const fft = new FFT(signal.length, 44100);\n fft.forward(signal);\n \n const spectrum = fft.spectrum;\n const barWidth = width / spectrum.length;\n \n for (let i = 0; i < spectrum.length; i++) {\n const barHeight = spectrum[i] * height;\n ctx.fillStyle = '#50e3c2';\n ctx.fillRect(i * barWidth, height - barHeight, barWidth, barHeight);\n }\n}\n\nfunction generateSignals() {\n const f1 = parseFloat(f1FrequencyInput.value);\n const f2 = parseFloat(f2FrequencyInput.value);\n const amplitude = parseFloat(amplitudeInput.value);\n const phase = parseFloat(phaseInput.value);\n \n f1Signal = generateSineWave(f1, amplitude, phase);\n f2Signal = generateSineWave(f2, amplitude, phase);\n \n plotTimeDomain(f1Signal, timeDomainCanvas);\n plotFrequencyDomain(f1Signal, frequencyDomainCanvas);\n}\n\nfunction addSignals() {\n combinedSignal = f1Signal.map((value, index) => value + f2Signal[index]);\n plotTimeDomain(combinedSignal, timeDomainCanvas);\n plotFrequencyDomain(combinedSignal, frequencyDomainCanvas);\n}\n\nfunction multiplySignals() {\n combinedSignal = f1Signal.map((value, index) => value * f2Signal[index]);\n plotTimeDomain(combinedSignal, timeDomainCanvas);\n plotFrequencyDomain(combinedSignal, frequencyDomainCanvas);\n}\n\nfunction subtractSignals() {\n combinedSignal = f1Signal.map((value, index) => value - f2Signal[index]);\n plotTimeDomain(combinedSignal, timeDomainCanvas);\n plotFrequencyDomain(combinedSignal, frequencyDomainCanvas);\n}\n\ngenerateBtn.addEventListener('click', generateSignals);\naddBtn.addEventListener('click', addSignals);\nmultiplyBtn.addEventListener('click', multiplySignals);\nsubtractBtn.addEventListener('click', subtractSignals);\n\n// FFT implementation\nclass FFT {\n constructor(bufferSize, sampleRate) {\n this.bufferSize = bufferSize;\n this.sampleRate = sampleRate;\n this.bandwidth = sampleRate / bufferSize;\n this.spectrum = new Float32Array(bufferSize / 2);\n this.real = new Float32Array(bufferSize);\n this.imag = new Float32Array(bufferSize);\n }\n\n forward(buffer) {\n this.real.set(buffer);\n this.imag.fill(0);\n this.transform(this.real, this.imag);\n this.calculateSpectrum();\n }\n\n transform(real, imag) {\n const n = real.length;\n if (n <= 1) return;\n\n const evenReal = new Float32Array(n / 2);\n const evenImag = new Float32Array(n / 2);\n const oddReal = new Float32Array(n / 2);\n const oddImag = new Float32Array(n / 2);\n\n for (let i = 0; i < n / 2; i++) {\n evenReal[i] = real[2 * i];\n evenImag[i] = imag[2 * i];\n oddReal[i] = real[2 * i + 1];\n oddImag[i] = imag[2 * i + 1];\n }\n\n this.transform(evenReal, evenImag);\n this.transform(oddReal, oddImag);\n\n for (let k = 0; k < n / 2; k++) {\n const tReal = Math.cos(2 * Math.PI * k / n) * oddReal[k] - Math.sin(2 * Math.PI * k / n) * oddImag[k];\n const tImag = Math.sin(2 * Math.PI * k / n) * oddReal[k] + Math.cos(2 * Math.PI * k / n) * oddImag[k];\n\n real[k] = evenReal[k] + tReal;\n imag[k] = evenImag[k] + tImag;\n real[k + n / 2] = evenReal[k] - tReal;\n imag[k + n / 2] = evenImag[k] - tImag;\n }\n }\n\n calculateSpectrum() {\n for (let i = 0; i < this.bufferSize / 2; i++) {\n this.spectrum[i] = Math.sqrt(this.real[i] * this.real[i] + this.imag[i] * this.imag[i]);\n }\n }\n}\n---end---"
+ },
+ "logprobs": null,
+ "finish_reason": "stop"
+ }
+ ],
+ "usage": {
+ "prompt_tokens": 283,
+ "completion_tokens": 2568,
+ "total_tokens": 2851,
+ "prompt_cache_hit_tokens": 0,
+ "prompt_cache_miss_tokens": 283
+ },
+ "system_fingerprint": "fp_f1afce2943"
+ }
readme.scroll
Changed around line 1
+ # signalgen.scroll.pub
+ Website generated by DeepSeek from prompt: Stw贸rz generator sygna艂贸w okresowych f1 oraz f2, oraz ich reprezentacj臋 widmow膮, dodaj odpowiednie parametry i podstawowe operacje na tych sygna艂ach. B膮d藕 kreatywny.
script.js
Changed around line 1
+ const f1FrequencyInput = document.getElementById('f1-frequency');
+ const f2FrequencyInput = document.getElementById('f2-frequency');
+ const amplitudeInput = document.getElementById('amplitude');
+ const phaseInput = document.getElementById('phase');
+ const generateBtn = document.getElementById('generate-btn');
+ const addBtn = document.getElementById('add-btn');
+ const multiplyBtn = document.getElementById('multiply-btn');
+ const subtractBtn = document.getElementById('subtract-btn');
+ const timeDomainCanvas = document.getElementById('time-domain');
+ const frequencyDomainCanvas = document.getElementById('frequency-domain');
+
+ let f1Signal = [];
+ let f2Signal = [];
+ let combinedSignal = [];
+
+ function generateSineWave(frequency, amplitude, phase, sampleRate = 44100, duration = 1) {
+ const signal = [];
+ const numSamples = sampleRate * duration;
+ for (let i = 0; i < numSamples; i++) {
+ const t = i / sampleRate;
+ signal.push(amplitude * Math.sin(2 * Math.PI * frequency * t + phase));
+ }
+ return signal;
+ }
+
+ function plotTimeDomain(signal, canvas) {
+ const ctx = canvas.getContext('2d');
+ const width = canvas.width;
+ const height = canvas.height;
+ ctx.clearRect(0, 0, width, height);
+ ctx.beginPath();
+ ctx.moveTo(0, height / 2);
+
+ const step = width / signal.length;
+ for (let i = 0; i < signal.length; i++) {
+ const x = i * step;
+ const y = height / 2 - signal[i] * (height / 4);
+ ctx.lineTo(x, y);
+ }
+
+ ctx.strokeStyle = '#4a90e2';
+ ctx.lineWidth = 2;
+ ctx.stroke();
+ }
+
+ function plotFrequencyDomain(signal, canvas) {
+ const ctx = canvas.getContext('2d');
+ const width = canvas.width;
+ const height = canvas.height;
+ ctx.clearRect(0, 0, width, height);
+
+ const fft = new FFT(signal.length, 44100);
+ fft.forward(signal);
+
+ const spectrum = fft.spectrum;
+ const barWidth = width / spectrum.length;
+
+ for (let i = 0; i < spectrum.length; i++) {
+ const barHeight = spectrum[i] * height;
+ ctx.fillStyle = '#50e3c2';
+ ctx.fillRect(i * barWidth, height - barHeight, barWidth, barHeight);
+ }
+ }
+
+ function generateSignals() {
+ const f1 = parseFloat(f1FrequencyInput.value);
+ const f2 = parseFloat(f2FrequencyInput.value);
+ const amplitude = parseFloat(amplitudeInput.value);
+ const phase = parseFloat(phaseInput.value);
+
+ f1Signal = generateSineWave(f1, amplitude, phase);
+ f2Signal = generateSineWave(f2, amplitude, phase);
+
+ plotTimeDomain(f1Signal, timeDomainCanvas);
+ plotFrequencyDomain(f1Signal, frequencyDomainCanvas);
+ }
+
+ function addSignals() {
+ combinedSignal = f1Signal.map((value, index) => value + f2Signal[index]);
+ plotTimeDomain(combinedSignal, timeDomainCanvas);
+ plotFrequencyDomain(combinedSignal, frequencyDomainCanvas);
+ }
+
+ function multiplySignals() {
+ combinedSignal = f1Signal.map((value, index) => value * f2Signal[index]);
+ plotTimeDomain(combinedSignal, timeDomainCanvas);
+ plotFrequencyDomain(combinedSignal, frequencyDomainCanvas);
+ }
+
+ function subtractSignals() {
+ combinedSignal = f1Signal.map((value, index) => value - f2Signal[index]);
+ plotTimeDomain(combinedSignal, timeDomainCanvas);
+ plotFrequencyDomain(combinedSignal, frequencyDomainCanvas);
+ }
+
+ generateBtn.addEventListener('click', generateSignals);
+ addBtn.addEventListener('click', addSignals);
+ multiplyBtn.addEventListener('click', multiplySignals);
+ subtractBtn.addEventListener('click', subtractSignals);
+
+ // FFT implementation
+ class FFT {
+ constructor(bufferSize, sampleRate) {
+ this.bufferSize = bufferSize;
+ this.sampleRate = sampleRate;
+ this.bandwidth = sampleRate / bufferSize;
+ this.spectrum = new Float32Array(bufferSize / 2);
+ this.real = new Float32Array(bufferSize);
+ this.imag = new Float32Array(bufferSize);
+ }
+
+ forward(buffer) {
+ this.real.set(buffer);
+ this.imag.fill(0);
+ this.transform(this.real, this.imag);
+ this.calculateSpectrum();
+ }
+
+ transform(real, imag) {
+ const n = real.length;
+ if (n <= 1) return;
+
+ const evenReal = new Float32Array(n / 2);
+ const evenImag = new Float32Array(n / 2);
+ const oddReal = new Float32Array(n / 2);
+ const oddImag = new Float32Array(n / 2);
+
+ for (let i = 0; i < n / 2; i++) {
+ evenReal[i] = real[2 * i];
+ evenImag[i] = imag[2 * i];
+ oddReal[i] = real[2 * i + 1];
+ oddImag[i] = imag[2 * i + 1];
+ }
+
+ this.transform(evenReal, evenImag);
+ this.transform(oddReal, oddImag);
+
+ for (let k = 0; k < n / 2; k++) {
+ const tReal = Math.cos(2 * Math.PI * k / n) * oddReal[k] - Math.sin(2 * Math.PI * k / n) * oddImag[k];
+ const tImag = Math.sin(2 * Math.PI * k / n) * oddReal[k] + Math.cos(2 * Math.PI * k / n) * oddImag[k];
+
+ real[k] = evenReal[k] + tReal;
+ imag[k] = evenImag[k] + tImag;
+ real[k + n / 2] = evenReal[k] - tReal;
+ imag[k + n / 2] = evenImag[k] - tImag;
+ }
+ }
+
+ calculateSpectrum() {
+ for (let i = 0; i < this.bufferSize / 2; i++) {
+ this.spectrum[i] = Math.sqrt(this.real[i] * this.real[i] + this.imag[i] * this.imag[i]);
+ }
+ }
+ }
style.css
Changed around line 1
+ :root {
+ --primary-color: #4a90e2;
+ --secondary-color: #50e3c2;
+ --background-color: #f5f7fa;
+ --text-color: #333;
+ --border-radius: 8px;
+ --box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
+ }
+
+ body {
+ font-family: 'Segoe UI', sans-serif;
+ line-height: 1.6;
+ margin: 0;
+ padding: 0;
+ background-color: var(--background-color);
+ color: var(--text-color);
+ }
+
+ header {
+ background: linear-gradient(135deg, var(--primary-color), var(--secondary-color));
+ color: white;
+ padding: 2rem;
+ text-align: center;
+ border-radius: 0 0 var(--border-radius) var(--border-radius);
+ }
+
+ main {
+ max-width: 1200px;
+ margin: 2rem auto;
+ padding: 0 1rem;
+ }
+
+ .controls {
+ background: white;
+ padding: 1.5rem;
+ border-radius: var(--border-radius);
+ box-shadow: var(--box-shadow);
+ margin-bottom: 2rem;
+ }
+
+ .input-group {
+ margin-bottom: 1rem;
+ }
+
+ label {
+ display: block;
+ margin-bottom: 0.5rem;
+ font-weight: 500;
+ }
+
+ input {
+ width: 100%;
+ padding: 0.5rem;
+ border: 1px solid #ddd;
+ border-radius: var(--border-radius);
+ }
+
+ button {
+ background-color: var(--primary-color);
+ color: white;
+ border: none;
+ padding: 0.75rem 1.5rem;
+ border-radius: var(--border-radius);
+ cursor: pointer;
+ transition: background-color 0.3s ease;
+ }
+
+ button:hover {
+ background-color: darken(var(--primary-color), 10%);
+ }
+
+ .visualization {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
+ gap: 2rem;
+ margin-bottom: 2rem;
+ }
+
+ .chart-container {
+ background: white;
+ padding: 1.5rem;
+ border-radius: var(--border-radius);
+ box-shadow: var(--box-shadow);
+ }
+
+ .operations {
+ text-align: center;
+ margin-bottom: 2rem;
+ }
+
+ .operation-buttons {
+ display: flex;
+ justify-content: center;
+ gap: 1rem;
+ flex-wrap: wrap;
+ }
+
+ footer {
+ text-align: center;
+ padding: 1rem;
+ background: white;
+ margin-top: 2rem;
+ border-radius: var(--border-radius) var(--border-radius) 0 0;
+ box-shadow: var(--box-shadow);
+ }
+
+ @media (max-width: 768px) {
+ .visualization {
+ grid-template-columns: 1fr;
+ }
+ }