Skip to content

Commit 4d4ff0b

Browse files
Implement ATSC 8-VSB demodulator module in TypeScript (#218)
* Initial plan * Implement ATSC 8-VSB demodulator with comprehensive tests Co-authored-by: alexthemitchell <5687158+alexthemitchell@users.noreply.github.com> * Add comprehensive documentation and usage examples for ATSC 8-VSB demodulator Co-authored-by: alexthemitchell <5687158+alexthemitchell@users.noreply.github.com> * Fix PR review issues: implement proper 64-tap FIR equalizer, improve sync detection, remove unused code Co-authored-by: alexthemitchell <5687158+alexthemitchell@users.noreply.github.com> * Address PR review feedback: fix comments, remove unused params, improve sync tracking Co-authored-by: alexthemitchell <5687158+alexthemitchell@users.noreply.github.com> * Fix lastSyncPosition tracking after buffer slicing Co-authored-by: alexthemitchell <5687158+alexthemitchell@users.noreply.github.com> * Fix TypeScript type errors and improve type safety Co-authored-by: alexthemitchell <5687158+alexthemitchell@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: alexthemitchell <5687158+alexthemitchell@users.noreply.github.com>
1 parent a834855 commit 4d4ff0b

File tree

5 files changed

+1569
-0
lines changed

5 files changed

+1569
-0
lines changed
Lines changed: 304 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,304 @@
1+
/**
2+
* ATSC 8-VSB Demodulator Usage Examples
3+
*
4+
* Demonstrates various usage patterns for the ATSC 8-VSB demodulator plugin.
5+
*/
6+
7+
/* eslint-disable no-console, @typescript-eslint/explicit-function-return-type, @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/prefer-for-of */
8+
9+
import { ATSC8VSBDemodulator } from "./ATSC8VSBDemodulator";
10+
import type { IQSample } from "../../models/SDRDevice";
11+
12+
/**
13+
* Example 1: Basic Demodulation
14+
*
15+
* Simple example showing basic setup and demodulation.
16+
*/
17+
export async function basicDemodulation() {
18+
// Create and initialize demodulator
19+
const demodulator = new ATSC8VSBDemodulator();
20+
await demodulator.initialize();
21+
await demodulator.activate();
22+
23+
// Simulate receiving IQ samples from SDR device
24+
const iqSamples: IQSample[] = [
25+
/* ... samples from SDR ... */
26+
];
27+
28+
// Demodulate to symbols
29+
const symbols = demodulator.demodulate(iqSamples);
30+
31+
console.log(`Demodulated ${symbols.length} symbols`);
32+
33+
// Clean up
34+
await demodulator.deactivate();
35+
}
36+
37+
/**
38+
* Example 2: Monitoring Sync Status
39+
*
40+
* Shows how to monitor sync lock and track segment/field boundaries.
41+
*/
42+
export async function monitorSyncStatus() {
43+
const demodulator = new ATSC8VSBDemodulator();
44+
await demodulator.initialize();
45+
await demodulator.activate();
46+
47+
// Process samples in a loop
48+
let processedSegments = 0;
49+
const targetSegments = 313; // One field
50+
51+
while (processedSegments < targetSegments) {
52+
// Get samples from SDR
53+
const iqSamples: IQSample[] = [
54+
/* ... samples ... */
55+
];
56+
57+
// Demodulate
58+
demodulator.demodulate(iqSamples);
59+
60+
// Check sync status
61+
if (demodulator.isSyncLocked()) {
62+
const segmentCount = demodulator.getSegmentSyncCount();
63+
const fieldCount = demodulator.getFieldSyncCount();
64+
65+
console.log(`Sync locked!`);
66+
console.log(`Segments: ${segmentCount}, Fields: ${fieldCount}`);
67+
68+
processedSegments = segmentCount;
69+
70+
// Check if we've completed a field
71+
if (fieldCount > 0) {
72+
console.log(`Completed field ${fieldCount}`);
73+
}
74+
} else {
75+
console.log("Searching for sync...");
76+
}
77+
}
78+
79+
await demodulator.deactivate();
80+
}
81+
82+
/**
83+
* Example 3: Custom Configuration
84+
*
85+
* Demonstrates configuring demodulator parameters.
86+
*/
87+
export async function customConfiguration() {
88+
const demodulator = new ATSC8VSBDemodulator();
89+
90+
// Configure before initialization
91+
demodulator.setParameters({
92+
audioSampleRate: 10.76e6, // 10.76 Msymbols/sec
93+
bandwidth: 6e6, // 6 MHz channel
94+
squelch: 10, // 10% squelch threshold
95+
afcEnabled: true, // Enable AFC
96+
});
97+
98+
await demodulator.initialize();
99+
await demodulator.activate();
100+
101+
// Verify configuration
102+
const config = demodulator.getParameters();
103+
console.log("Demodulator configuration:", config);
104+
105+
// Process samples...
106+
await demodulator.deactivate();
107+
}
108+
109+
/**
110+
* Example 4: Real-time Processing with SDR
111+
*
112+
* Shows integration with SDR device for real-time ATSC reception.
113+
*/
114+
export async function realtimeProcessing() {
115+
const demodulator = new ATSC8VSBDemodulator();
116+
117+
// Configure for real-time operation
118+
demodulator.setParameters({
119+
audioSampleRate: 10.76e6,
120+
bandwidth: 6e6,
121+
afcEnabled: true,
122+
});
123+
124+
await demodulator.initialize();
125+
await demodulator.activate();
126+
127+
// Simulate SDR streaming
128+
const processChunk = (iqSamples: IQSample[]) => {
129+
// Demodulate chunk
130+
const symbols = demodulator.demodulate(iqSamples);
131+
132+
// Process symbols (e.g., send to decoder)
133+
if (symbols.length > 0) {
134+
// Forward to Reed-Solomon decoder, etc.
135+
console.log(`Processed ${symbols.length} symbols`);
136+
}
137+
138+
return symbols;
139+
};
140+
141+
// Process multiple chunks
142+
for (let i = 0; i < 10; i++) {
143+
const chunk: IQSample[] = [
144+
/* ... get from SDR ... */
145+
];
146+
processChunk(chunk);
147+
}
148+
149+
await demodulator.deactivate();
150+
}
151+
152+
/**
153+
* Example 5: Performance Monitoring
154+
*
155+
* Demonstrates measuring demodulator performance.
156+
*/
157+
export async function performanceMonitoring() {
158+
const demodulator = new ATSC8VSBDemodulator();
159+
await demodulator.initialize();
160+
await demodulator.activate();
161+
162+
// Generate test samples
163+
const numSamples = 10000;
164+
const testSamples: IQSample[] = new Array(numSamples);
165+
for (let i = 0; i < numSamples; i++) {
166+
const level = (i % 8) - 3.5;
167+
testSamples[i] = { I: level, Q: 0 };
168+
}
169+
170+
// Measure processing time
171+
const startTime = performance.now();
172+
const symbols = demodulator.demodulate(testSamples);
173+
const endTime = performance.now();
174+
175+
const processingTime = endTime - startTime;
176+
const samplesPerSecond = (numSamples / processingTime) * 1000;
177+
178+
console.log(`Processing time: ${processingTime.toFixed(2)} ms`);
179+
console.log(`Throughput: ${(samplesPerSecond / 1e6).toFixed(2)} Msamples/s`);
180+
console.log(`Output symbols: ${symbols.length}`);
181+
182+
await demodulator.deactivate();
183+
}
184+
185+
/**
186+
* Example 6: Error Handling
187+
*
188+
* Shows proper error handling and recovery.
189+
*/
190+
export async function errorHandling() {
191+
const demodulator = new ATSC8VSBDemodulator();
192+
193+
try {
194+
await demodulator.initialize();
195+
await demodulator.activate();
196+
197+
// Try to set invalid mode
198+
try {
199+
demodulator.setMode("invalid");
200+
} catch (error) {
201+
console.error("Invalid mode error:", error);
202+
// Continue with default mode
203+
}
204+
205+
// Process samples
206+
const samples: IQSample[] = [
207+
/* ... */
208+
];
209+
const symbols = demodulator.demodulate(samples);
210+
211+
console.log(`Successfully demodulated ${symbols.length} symbols`);
212+
} catch (error) {
213+
console.error("Demodulation error:", error);
214+
} finally {
215+
// Always clean up
216+
await demodulator.deactivate();
217+
}
218+
}
219+
220+
/**
221+
* Example 7: Batch Processing
222+
*
223+
* Efficient batch processing of recorded samples.
224+
*/
225+
export async function batchProcessing() {
226+
const demodulator = new ATSC8VSBDemodulator();
227+
await demodulator.initialize();
228+
await demodulator.activate();
229+
230+
// Simulate batches of recorded samples
231+
const batches: IQSample[][] = [
232+
/* ... array of sample batches ... */
233+
];
234+
235+
const allSymbols: number[] = [];
236+
237+
for (const batch of batches) {
238+
const symbols = demodulator.demodulate(batch);
239+
240+
// Collect all symbols
241+
for (let i = 0; i < symbols.length; i++) {
242+
const symbol = symbols[i];
243+
if (symbol !== undefined) {
244+
allSymbols.push(symbol);
245+
}
246+
}
247+
248+
// Check progress
249+
if (demodulator.isSyncLocked()) {
250+
console.log(
251+
`Batch processed. Total segments: ${demodulator.getSegmentSyncCount()}`,
252+
);
253+
}
254+
}
255+
256+
console.log(`Total symbols demodulated: ${allSymbols.length}`);
257+
258+
await demodulator.deactivate();
259+
}
260+
261+
/**
262+
* Example 8: Plugin Registry Integration
263+
*
264+
* Shows how to use the demodulator with the plugin registry.
265+
*/
266+
export async function pluginRegistryIntegration() {
267+
// This would typically be in your main application code
268+
const { pluginRegistry } = await import("../../lib/PluginRegistry");
269+
270+
// Create and register demodulator
271+
const demodulator = new ATSC8VSBDemodulator();
272+
await pluginRegistry.register(demodulator);
273+
274+
// Get the registered demodulator
275+
const registered = pluginRegistry.getPlugin("atsc-8vsb-demodulator");
276+
277+
if (registered) {
278+
console.log("Demodulator registered:", registered.metadata);
279+
280+
// Activate
281+
await registered.activate();
282+
283+
// Use it...
284+
// const symbols = (registered as ATSC8VSBDemodulator).demodulate(samples);
285+
286+
// Deactivate
287+
await registered.deactivate();
288+
289+
// Unregister/cleanup
290+
await pluginRegistry.unregister(registered.metadata.id);
291+
}
292+
}
293+
294+
// Export all examples
295+
export const examples = {
296+
basicDemodulation,
297+
monitorSyncStatus,
298+
customConfiguration,
299+
realtimeProcessing,
300+
performanceMonitoring,
301+
errorHandling,
302+
batchProcessing,
303+
pluginRegistryIntegration,
304+
};

0 commit comments

Comments
 (0)