@rfkit/spectrum-analyzer 0.1.26 → 0.1.28
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/core/LevelStreamAnalyzer/index.d.ts +3 -1
- package/core/LevelStreamAnalyzer/index.d.ts.map +1 -1
- package/core/LevelStreamAnalyzer/types.d.ts +1 -0
- package/core/LevelStreamAnalyzer/types.d.ts.map +1 -1
- package/core/SeriesManager/constants.d.ts +10 -0
- package/core/SeriesManager/constants.d.ts.map +1 -0
- package/core/SeriesManager/index.d.ts +112 -0
- package/core/SeriesManager/index.d.ts.map +1 -0
- package/core/SeriesManager/types.d.ts +43 -0
- package/core/SeriesManager/types.d.ts.map +1 -0
- package/core/SpectrumAnalyzer/index.d.ts +19 -11
- package/core/SpectrumAnalyzer/index.d.ts.map +1 -1
- package/core/SpectrumAnalyzer/tools.d.ts +6 -0
- package/core/SpectrumAnalyzer/tools.d.ts.map +1 -1
- package/core/SpectrumAnalyzer/types.d.ts +14 -0
- package/core/SpectrumAnalyzer/types.d.ts.map +1 -1
- package/index.d.ts +3 -0
- package/index.d.ts.map +1 -1
- package/index.js +1 -1
- package/package.json +1 -1
|
@@ -17,8 +17,9 @@ export default class LevelStreamAnalyzer {
|
|
|
17
17
|
/**
|
|
18
18
|
* 处理一个新的电平值,更新频谱数据并重新计算概率。
|
|
19
19
|
* @param level 新的电平值
|
|
20
|
+
* @param timestamp 时间戳
|
|
20
21
|
*/
|
|
21
|
-
process(level: number): void;
|
|
22
|
+
process(level: number, timestamp: number): void;
|
|
22
23
|
/**
|
|
23
24
|
* 更新新数据对应的区间概率
|
|
24
25
|
* @param level 新的电平值
|
|
@@ -36,6 +37,7 @@ export default class LevelStreamAnalyzer {
|
|
|
36
37
|
/**
|
|
37
38
|
* 添加新的电平值到频谱数据中。
|
|
38
39
|
* @param level 新的电平值
|
|
40
|
+
* @param timestamp 时间戳
|
|
39
41
|
*/
|
|
40
42
|
private addNewData;
|
|
41
43
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/LevelStreamAnalyzer/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAEjD;;;GAGG;AACH,MAAM,CAAC,OAAO,OAAO,mBAAmB;IAEtC,SAAS,CAAC,MAAM,EAAE,QAAQ,CAAC,iBAAiB,CAAC,CAAC;IAE9C,OAAO,CAAC,YAAY,CAA8C;IAElE,OAAO,CAAC,eAAe,CAAkC;IAEzD,OAAO,CAAC,KAAK,CAAK;gBAEN,MAAM,EAAE,iBAAiB;IAQrC;;OAEG;IACI,KAAK,IAAI,IAAI;IAMb,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC,iBAAiB,CAAC,GAAG,IAAI;IAmB1D
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/LevelStreamAnalyzer/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAEjD;;;GAGG;AACH,MAAM,CAAC,OAAO,OAAO,mBAAmB;IAEtC,SAAS,CAAC,MAAM,EAAE,QAAQ,CAAC,iBAAiB,CAAC,CAAC;IAE9C,OAAO,CAAC,YAAY,CAA8C;IAElE,OAAO,CAAC,eAAe,CAAkC;IAEzD,OAAO,CAAC,KAAK,CAAK;gBAEN,MAAM,EAAE,iBAAiB;IAQrC;;OAEG;IACI,KAAK,IAAI,IAAI;IAMb,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC,iBAAiB,CAAC,GAAG,IAAI;IAmB1D;;;;OAIG;IACI,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI;IAOtD;;;OAGG;IACH,OAAO,CAAC,iBAAiB;IAWzB;;;OAGG;IACI,MAAM,IAAI,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC;IAIpC;;OAEG;IACH,OAAO,CAAC,iBAAiB;IA0BzB;;;;OAIG;IACH,OAAO,CAAC,UAAU;IAIlB;;OAEG;IACH,OAAO,CAAC,UAAU;CA6BnB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/core/LevelStreamAnalyzer/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxB,mBAAmB,EAAE,CAAC,IAAI,EAAE,qBAAqB,KAAK,IAAI,CAAC;CAC5D;AAED,MAAM,WAAW,qBAAqB;IACpC,oBAAoB,EAAE,YAAY,CAAC;IACnC,YAAY,EAAE,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/core/LevelStreamAnalyzer/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxB,mBAAmB,EAAE,CAAC,IAAI,EAAE,qBAAqB,KAAK,IAAI,CAAC;CAC5D;AAED,MAAM,WAAW,qBAAqB;IACpC,oBAAoB,EAAE,YAAY,CAAC;IACnC,YAAY,EAAE,YAAY,CAAC;IAC3B,aAAa,EAAE,YAAY,CAAC;CAC7B"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { GraphicType, OrientationType } from './types';
|
|
2
|
+
export declare const DEFAULT_SERIES_CONFIG: {
|
|
3
|
+
readonly thickness: 1;
|
|
4
|
+
readonly orientation: OrientationType.Horizontal;
|
|
5
|
+
readonly display: true;
|
|
6
|
+
readonly type: GraphicType.Line;
|
|
7
|
+
readonly color: "#00000000";
|
|
8
|
+
readonly label: "";
|
|
9
|
+
};
|
|
10
|
+
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../src/core/SeriesManager/constants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAEvD,eAAO,MAAM,qBAAqB;;;;;;;CAOxB,CAAC"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import type { SeriesChangeCallback, SeriesConfig, SeriesSubscriber, SubscriptionOptions } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Series 处理工具,用于管理图形系列的配置
|
|
4
|
+
* 支持初始化、属性设置、变更回调和订阅功能
|
|
5
|
+
*/
|
|
6
|
+
export default class SeriesManager {
|
|
7
|
+
private seriesMap;
|
|
8
|
+
private changeCallbacks;
|
|
9
|
+
private subscribers;
|
|
10
|
+
/**
|
|
11
|
+
* 构造函数,支持初始化系列配置
|
|
12
|
+
* @param initialSeries 初始系列配置数组
|
|
13
|
+
*/
|
|
14
|
+
constructor(initialSeries?: SeriesConfig[]);
|
|
15
|
+
/**
|
|
16
|
+
* 初始化系列配置
|
|
17
|
+
* @param seriesConfigs 系列配置数组
|
|
18
|
+
*/
|
|
19
|
+
private initializeSeries;
|
|
20
|
+
/**
|
|
21
|
+
* 添加新的系列配置
|
|
22
|
+
* @param config 系列配置
|
|
23
|
+
*/
|
|
24
|
+
addSeries(config: SeriesConfig): void;
|
|
25
|
+
/**
|
|
26
|
+
* 获取指定名称的系列配置
|
|
27
|
+
* @param name 系列名称
|
|
28
|
+
* @returns 系列配置或 undefined
|
|
29
|
+
*/
|
|
30
|
+
getSeries(name: string): SeriesConfig | undefined;
|
|
31
|
+
/**
|
|
32
|
+
* 获取所有系列配置
|
|
33
|
+
* @returns 所有系列配置的数组
|
|
34
|
+
*/
|
|
35
|
+
getAllSeries(): SeriesConfig[];
|
|
36
|
+
/**
|
|
37
|
+
* 获取当前所有配置
|
|
38
|
+
* @returns 包含所有系列配置的对象,以系列名为键
|
|
39
|
+
*/
|
|
40
|
+
getAllConfigs(): Record<string, SeriesConfig>;
|
|
41
|
+
/**
|
|
42
|
+
* 设置指定系列的某个属性
|
|
43
|
+
* @param name 系列名称
|
|
44
|
+
* @param property 属性名
|
|
45
|
+
* @param value 属性值
|
|
46
|
+
* @returns 是否设置成功
|
|
47
|
+
*/
|
|
48
|
+
setSeriesProperty<K extends keyof SeriesConfig>(name: string, property: K, value: SeriesConfig[K]): boolean;
|
|
49
|
+
/**
|
|
50
|
+
* 删除指定名称的系列
|
|
51
|
+
* @param name 系列名称
|
|
52
|
+
* @returns 是否删除成功
|
|
53
|
+
*/
|
|
54
|
+
removeSeries(name: string): boolean;
|
|
55
|
+
/**
|
|
56
|
+
* 检查系列是否存在
|
|
57
|
+
* @param name 系列名称
|
|
58
|
+
* @returns 是否存在
|
|
59
|
+
*/
|
|
60
|
+
hasSeries(name: string): boolean;
|
|
61
|
+
/**
|
|
62
|
+
* 添加变更回调函数
|
|
63
|
+
* @param callback 回调函数
|
|
64
|
+
*/
|
|
65
|
+
onChange(callback: SeriesChangeCallback): void;
|
|
66
|
+
/**
|
|
67
|
+
* 移除变更回调函数
|
|
68
|
+
* @param callback 要移除的回调函数
|
|
69
|
+
*/
|
|
70
|
+
offChange(callback: SeriesChangeCallback): void;
|
|
71
|
+
/**
|
|
72
|
+
* 通知所有回调函数属性变更
|
|
73
|
+
* @param name 系列名称
|
|
74
|
+
* @param property 属性名
|
|
75
|
+
* @param value 新值
|
|
76
|
+
*/
|
|
77
|
+
private notifyChange;
|
|
78
|
+
/**
|
|
79
|
+
* 清空所有系列配置
|
|
80
|
+
*/
|
|
81
|
+
clear(): void;
|
|
82
|
+
/**
|
|
83
|
+
* 获取系列数量
|
|
84
|
+
* @returns 系列数量
|
|
85
|
+
*/
|
|
86
|
+
size(): number;
|
|
87
|
+
/**
|
|
88
|
+
* 订阅系列变更事件
|
|
89
|
+
* @param subscriber 订阅回调函数
|
|
90
|
+
* @param options 订阅选项
|
|
91
|
+
* @returns 取消订阅的函数
|
|
92
|
+
*/
|
|
93
|
+
subscribe(subscriber: SeriesSubscriber, options?: SubscriptionOptions): () => void;
|
|
94
|
+
/**
|
|
95
|
+
* 取消订阅
|
|
96
|
+
* @param subscriber 要取消的订阅回调函数
|
|
97
|
+
*/
|
|
98
|
+
unsubscribe(subscriber: SeriesSubscriber): void;
|
|
99
|
+
/**
|
|
100
|
+
* 发送事件给所有订阅者
|
|
101
|
+
* @param event 事件数据
|
|
102
|
+
*/
|
|
103
|
+
private emitEvent;
|
|
104
|
+
/**
|
|
105
|
+
* 判断是否应该通知订阅者
|
|
106
|
+
* @param subscriber 订阅者
|
|
107
|
+
* @param event 事件数据
|
|
108
|
+
* @returns 是否应该通知
|
|
109
|
+
*/
|
|
110
|
+
private shouldNotifySubscriber;
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/SeriesManager/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,oBAAoB,EACpB,YAAY,EAEZ,gBAAgB,EAChB,mBAAmB,EACpB,MAAM,SAAS,CAAC;AAGjB;;;GAGG;AACH,MAAM,CAAC,OAAO,OAAO,aAAa;IAEhC,OAAO,CAAC,SAAS,CAAwC;IAEzD,OAAO,CAAC,eAAe,CAA8B;IAErD,OAAO,CAAC,WAAW,CAAyD;IAE5E;;;OAGG;gBACS,aAAa,GAAE,YAAY,EAAO;IAI9C;;;OAGG;IACH,OAAO,CAAC,gBAAgB;IAMxB;;;OAGG;IACI,SAAS,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI;IAgB5C;;;;OAIG;IACI,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS;IAIxD;;;OAGG;IACI,YAAY,IAAI,YAAY,EAAE;IAIrC;;;OAGG;IACI,aAAa,IAAI,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC;IAQpD;;;;;;OAMG;IACI,iBAAiB,CAAC,CAAC,SAAS,MAAM,YAAY,EACnD,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,CAAC,EACX,KAAK,EAAE,YAAY,CAAC,CAAC,CAAC,GACrB,OAAO;IAiCV;;;;OAIG;IACI,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAoB1C;;;;OAIG;IACI,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAIvC;;;OAGG;IACI,QAAQ,CAAC,QAAQ,EAAE,oBAAoB,GAAG,IAAI;IAIrD;;;OAGG;IACI,SAAS,CAAC,QAAQ,EAAE,oBAAoB,GAAG,IAAI;IAOtD;;;;;OAKG;IACH,OAAO,CAAC,YAAY;IAUpB;;OAEG;IACI,KAAK,IAAI,IAAI;IASpB;;;OAGG;IACI,IAAI,IAAI,MAAM;IAIrB;;;;;OAKG;IACI,SAAS,CACd,UAAU,EAAE,gBAAgB,EAC5B,OAAO,GAAE,mBAAwB,GAChC,MAAM,IAAI;IA4Bb;;;OAGG;IACI,WAAW,CAAC,UAAU,EAAE,gBAAgB,GAAG,IAAI;IAItD;;;OAGG;IACH,OAAO,CAAC,SAAS;IASjB;;;;;OAKG;IACH,OAAO,CAAC,sBAAsB;CAuB/B"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
export interface SeriesConfig {
|
|
2
|
+
readonly name: string;
|
|
3
|
+
label: string;
|
|
4
|
+
color: string;
|
|
5
|
+
display: boolean;
|
|
6
|
+
type: GraphicType;
|
|
7
|
+
thickness?: number;
|
|
8
|
+
orientation?: OrientationType;
|
|
9
|
+
}
|
|
10
|
+
export declare enum OrientationType {
|
|
11
|
+
Horizontal = "horizontal",
|
|
12
|
+
Vertical = "vertical"
|
|
13
|
+
}
|
|
14
|
+
export declare enum GraphicType {
|
|
15
|
+
Circle = "circle",
|
|
16
|
+
Rect = "rect",
|
|
17
|
+
Line = "line",
|
|
18
|
+
Stepline = "stepline",
|
|
19
|
+
Bar = "bar",
|
|
20
|
+
Area = "area"
|
|
21
|
+
}
|
|
22
|
+
export type SeriesChangeCallback = (name: string, property: keyof SeriesConfig, value: SeriesConfig[keyof SeriesConfig]) => void;
|
|
23
|
+
export declare enum SeriesEventType {
|
|
24
|
+
PropertyChanged = "propertyChanged",
|
|
25
|
+
SeriesAdded = "seriesAdded",
|
|
26
|
+
SeriesRemoved = "seriesRemoved",
|
|
27
|
+
SeriesCleared = "seriesCleared"
|
|
28
|
+
}
|
|
29
|
+
export interface SeriesEventData {
|
|
30
|
+
type: SeriesEventType;
|
|
31
|
+
name?: string;
|
|
32
|
+
property?: keyof SeriesConfig;
|
|
33
|
+
value?: SeriesConfig[keyof SeriesConfig];
|
|
34
|
+
oldValue?: SeriesConfig[keyof SeriesConfig];
|
|
35
|
+
series?: SeriesConfig;
|
|
36
|
+
}
|
|
37
|
+
export type SeriesSubscriber = (event: SeriesEventData) => void;
|
|
38
|
+
export interface SubscriptionOptions {
|
|
39
|
+
immediate?: boolean;
|
|
40
|
+
eventTypes?: SeriesEventType[];
|
|
41
|
+
seriesNames?: string[];
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/core/SeriesManager/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IAEd,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,WAAW,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,eAAe,CAAC;CAC/B;AAED,oBAAY,eAAe;IACzB,UAAU,eAAe;IACzB,QAAQ,aAAa;CACtB;AAED,oBAAY,WAAW;IACrB,MAAM,WAAW;IACjB,IAAI,SAAS;IACb,IAAI,SAAS;IACb,QAAQ,aAAa;IACrB,GAAG,QAAQ;IACX,IAAI,SAAS;CACd;AAED,MAAM,MAAM,oBAAoB,GAAG,CACjC,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,YAAY,EAC5B,KAAK,EAAE,YAAY,CAAC,MAAM,YAAY,CAAC,KACpC,IAAI,CAAC;AAGV,oBAAY,eAAe;IACzB,eAAe,oBAAoB;IACnC,WAAW,gBAAgB;IAC3B,aAAa,kBAAkB;IAC/B,aAAa,kBAAkB;CAChC;AAGD,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,eAAe,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,YAAY,CAAC;IAC9B,KAAK,CAAC,EAAE,YAAY,CAAC,MAAM,YAAY,CAAC,CAAC;IACzC,QAAQ,CAAC,EAAE,YAAY,CAAC,MAAM,YAAY,CAAC,CAAC;IAC5C,MAAM,CAAC,EAAE,YAAY,CAAC;CACvB;AAGD,MAAM,MAAM,gBAAgB,GAAG,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,CAAC;AAGhE,MAAM,WAAW,mBAAmB;IAClC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,UAAU,CAAC,EAAE,eAAe,EAAE,CAAC;IAC/B,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;CACxB"}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import type { isValidFloat32Array, ProcessInput, ScanSegment, SpectrumConfig,
|
|
1
|
+
import type { isValidFloat32Array, ProcessInput, ScanSegment, SpectrumConfig, SpectrumOutputData, TemplateOverData, TimestampedFloat32Array } from './types';
|
|
2
|
+
import { ExtraDataMode } from './types';
|
|
2
3
|
export default class SpectrumAnalyzer {
|
|
3
|
-
|
|
4
|
+
config: Required<Omit<SpectrumConfig, 'segments' | 'bandwidthConfig' | 'onSpectrumUpdate'>>;
|
|
4
5
|
private segments;
|
|
5
|
-
|
|
6
|
-
|
|
6
|
+
antennaFactorData: Float32Array;
|
|
7
|
+
antennaFactorSwitch: boolean;
|
|
7
8
|
protected realData: TimestampedFloat32Array;
|
|
8
9
|
protected maxData: isValidFloat32Array;
|
|
9
10
|
protected minData: isValidFloat32Array;
|
|
@@ -11,7 +12,7 @@ export default class SpectrumAnalyzer {
|
|
|
11
12
|
protected templateData: Float32Array;
|
|
12
13
|
protected backgroundNoiseData: Float32Array;
|
|
13
14
|
protected waterfallData: TimestampedFloat32Array[];
|
|
14
|
-
|
|
15
|
+
srcIndexCache: Uint32Array;
|
|
15
16
|
protected realOutputData: Float32Array;
|
|
16
17
|
protected waterfallOutputData: TimestampedFloat32Array[];
|
|
17
18
|
protected scanProgress: number;
|
|
@@ -21,6 +22,8 @@ export default class SpectrumAnalyzer {
|
|
|
21
22
|
protected cachedExceedingDatas: TemplateOverData[];
|
|
22
23
|
protected fluorescenceData?: Map<number, number>[];
|
|
23
24
|
protected fluorescenceMaxCount: number;
|
|
25
|
+
extraData: Record<string, Float32Array>;
|
|
26
|
+
protected extraOutputData: Record<string, Float32Array>;
|
|
24
27
|
private readonly onSpectrumUpdate?;
|
|
25
28
|
constructor(config: Partial<SpectrumConfig>);
|
|
26
29
|
/**
|
|
@@ -71,12 +74,13 @@ export default class SpectrumAnalyzer {
|
|
|
71
74
|
/**
|
|
72
75
|
* 重置频谱分析器的状态,包括数据和进度。
|
|
73
76
|
*/
|
|
74
|
-
reset(): void;
|
|
75
77
|
/**
|
|
76
|
-
*
|
|
77
|
-
* @
|
|
78
|
+
* 设置额外数据
|
|
79
|
+
* @param data 数据对象
|
|
80
|
+
* @param mode 操作模式:ExtraDataMode.REPLACE(替换全部), ExtraDataMode.MERGE(合并), ExtraDataMode.UPDATE(更新已存在的键)
|
|
78
81
|
*/
|
|
79
|
-
|
|
82
|
+
setExtraData(data: Record<string, Float32Array | number[]> | null, mode?: ExtraDataMode): void;
|
|
83
|
+
reset(): void;
|
|
80
84
|
/**
|
|
81
85
|
* 获取频谱分析器的性能指标,包括处理时间、数据点数、瀑布图帧数、初始化状态和内存使用情况。
|
|
82
86
|
* @returns {Readonly<Record<string, number | boolean>>} - 包含性能指标的对象。
|
|
@@ -108,9 +112,14 @@ export default class SpectrumAnalyzer {
|
|
|
108
112
|
private updateTemplateOverData;
|
|
109
113
|
/**
|
|
110
114
|
* 对数据进行重采样,生成频谱输出数据。
|
|
115
|
+
* @param {boolean} skipExtraData - 是否跳过 extraData 处理,默认 false
|
|
111
116
|
* @returns {Readonly<SpectrumOutputData>} - 包含重采样后的实时数据、最大值、最小值和平均值的对象。
|
|
112
117
|
*/
|
|
113
118
|
protected resampleDataSeries(): Readonly<SpectrumOutputData>;
|
|
119
|
+
/**
|
|
120
|
+
* 处理 extraData 的重采样,生成 extraOutputData
|
|
121
|
+
* 利用现有的 srcIndexCache 进行高效重采样
|
|
122
|
+
*/
|
|
114
123
|
/**
|
|
115
124
|
* 对瀑布图输出数据进行重采样。
|
|
116
125
|
*/
|
|
@@ -144,7 +153,6 @@ export default class SpectrumAnalyzer {
|
|
|
144
153
|
* 优化版本:减少不必要的计算和内存访问
|
|
145
154
|
*/
|
|
146
155
|
private updateFluorescenceStats;
|
|
147
|
-
private isAllValid;
|
|
148
156
|
/**
|
|
149
157
|
* 通知频谱数据更新,调用回调函数。
|
|
150
158
|
* @param {SpectrumOutputData} processedData - 处理后的频谱数据。
|
|
@@ -171,6 +179,6 @@ export default class SpectrumAnalyzer {
|
|
|
171
179
|
* 获取所有原始数据,包括实时数据、最大值、最小值、平均值、模板数据、背景噪声数据和瀑布图数据。
|
|
172
180
|
* 注意:返回的是原始数据的引用,修改这些数据会直接影响分析器内部状态。
|
|
173
181
|
*/
|
|
174
|
-
getAllRawData(): Readonly<
|
|
182
|
+
getAllRawData(): Readonly<SpectrumOutputData>;
|
|
175
183
|
}
|
|
176
184
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/SpectrumAnalyzer/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/SpectrumAnalyzer/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -40,6 +40,11 @@ export declare const resampleMultiple: ({ antennaFactorData, antennaFactorSwitch
|
|
|
40
40
|
srcIndexCache: Uint32Array;
|
|
41
41
|
fluorescenceOutputData: Map<number, number>[];
|
|
42
42
|
};
|
|
43
|
+
/**
|
|
44
|
+
* 专门用于处理 extraData 的重采样,支持天线因子应用
|
|
45
|
+
* 高性能优化版本:预分配内存,消除重复代码
|
|
46
|
+
*/
|
|
47
|
+
export declare const resampleExtraData: (extraData: Record<string, Float32Array>, antennaFactorData: Float32Array, antennaFactorSwitch: boolean, srcIndexCache: Uint32Array) => Record<string, Float32Array>;
|
|
43
48
|
export declare const findExceedingDatas: ({ realData, maxData, minData, templateData }: {
|
|
44
49
|
realData: TimestampedFloat32Array;
|
|
45
50
|
maxData: Float32Array;
|
|
@@ -55,4 +60,5 @@ export declare const findExceedingDatasIncremental: ({ realData, maxData, minDat
|
|
|
55
60
|
endIndex: number;
|
|
56
61
|
previousSegments?: TemplateOverData[];
|
|
57
62
|
}) => TemplateOverData[];
|
|
63
|
+
export declare function isAllValid(arr: Float32Array): boolean;
|
|
58
64
|
//# sourceMappingURL=tools.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../../src/core/SpectrumAnalyzer/tools.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,MAAM,SAAS,CAAC;AAGzE,eAAO,MAAM,kBAAkB,GAC7B,QAAQ,YAAY,GAAG;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,EACD,QAAQ,YAAY,GAAG;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,SAMF,CAAC;AAEF,eAAO,MAAM,QAAQ,GAAI,oEAKtB;IACD,QAAQ,EAAE,uBAAuB,CAAC;IAClC,iBAAiB,EAAE,YAAY,CAAC;IAChC,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,YAAY,EAAE,MAAM,CAAC;CACtB,KAAG;IAAE,cAAc,EAAE,uBAAuB,CAAC;IAAC,aAAa,EAAE,WAAW,CAAA;CA6DxE,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAAI,oJAc9B;IACD,iBAAiB,EAAE,YAAY,CAAC;IAChC,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,uBAAuB,CAAC;IAClC,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,mBAAmB,CAAC,EAAE,YAAY,CAAC;IACnC,gBAAgB,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC;CAC1C,KAAG;IACF,cAAc,EAAE,uBAAuB,CAAC;IACxC,aAAa,EAAE,YAAY,CAAC;IAC5B,aAAa,EAAE,YAAY,CAAC;IAC5B,aAAa,EAAE,YAAY,CAAC;IAC5B,kBAAkB,EAAE,YAAY,CAAC;IACjC,yBAAyB,EAAE,YAAY,CAAC;IACxC,aAAa,EAAE,WAAW,CAAC;IAC3B,sBAAsB,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC;CA8K/C,CAAC;AA+IF,eAAO,MAAM,kBAAkB,GAAI,8CAKhC;IACD,QAAQ,EAAE,uBAAuB,CAAC;IAClC,OAAO,EAAE,YAAY,CAAC;IACtB,OAAO,EAAE,YAAY,CAAC;IACtB,YAAY,EAAE,YAAY,CAAC;CAC5B,KAAG,gBAAgB,EAanB,CAAC;AAGF,eAAO,MAAM,6BAA6B,GAAI,sFAQ3C;IACD,QAAQ,EAAE,uBAAuB,CAAC;IAClC,OAAO,EAAE,YAAY,CAAC;IACtB,OAAO,EAAE,YAAY,CAAC;IACtB,YAAY,EAAE,YAAY,CAAC;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,CAAC,EAAE,gBAAgB,EAAE,CAAC;CACvC,KAAG,gBAAgB,EAgBnB,CAAC"}
|
|
1
|
+
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../../src/core/SpectrumAnalyzer/tools.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,MAAM,SAAS,CAAC;AAGzE,eAAO,MAAM,kBAAkB,GAC7B,QAAQ,YAAY,GAAG;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,EACD,QAAQ,YAAY,GAAG;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,SAMF,CAAC;AAEF,eAAO,MAAM,QAAQ,GAAI,oEAKtB;IACD,QAAQ,EAAE,uBAAuB,CAAC;IAClC,iBAAiB,EAAE,YAAY,CAAC;IAChC,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,YAAY,EAAE,MAAM,CAAC;CACtB,KAAG;IAAE,cAAc,EAAE,uBAAuB,CAAC;IAAC,aAAa,EAAE,WAAW,CAAA;CA6DxE,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAAI,oJAc9B;IACD,iBAAiB,EAAE,YAAY,CAAC;IAChC,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,uBAAuB,CAAC;IAClC,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,mBAAmB,CAAC,EAAE,YAAY,CAAC;IACnC,gBAAgB,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC;CAC1C,KAAG;IACF,cAAc,EAAE,uBAAuB,CAAC;IACxC,aAAa,EAAE,YAAY,CAAC;IAC5B,aAAa,EAAE,YAAY,CAAC;IAC5B,aAAa,EAAE,YAAY,CAAC;IAC5B,kBAAkB,EAAE,YAAY,CAAC;IACjC,yBAAyB,EAAE,YAAY,CAAC;IACxC,aAAa,EAAE,WAAW,CAAC;IAC3B,sBAAsB,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC;CA8K/C,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,iBAAiB,GAC5B,WAAW,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,EACvC,mBAAmB,YAAY,EAC/B,qBAAqB,OAAO,EAC5B,eAAe,WAAW,KACzB,MAAM,CAAC,MAAM,EAAE,YAAY,CAmC7B,CAAC;AA+IF,eAAO,MAAM,kBAAkB,GAAI,8CAKhC;IACD,QAAQ,EAAE,uBAAuB,CAAC;IAClC,OAAO,EAAE,YAAY,CAAC;IACtB,OAAO,EAAE,YAAY,CAAC;IACtB,YAAY,EAAE,YAAY,CAAC;CAC5B,KAAG,gBAAgB,EAanB,CAAC;AAGF,eAAO,MAAM,6BAA6B,GAAI,sFAQ3C;IACD,QAAQ,EAAE,uBAAuB,CAAC;IAClC,OAAO,EAAE,YAAY,CAAC;IACtB,OAAO,EAAE,YAAY,CAAC;IACtB,YAAY,EAAE,YAAY,CAAC;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,CAAC,EAAE,gBAAgB,EAAE,CAAC;CACvC,KAAG,gBAAgB,EAgBnB,CAAC;AAEF,wBAAgB,UAAU,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAOrD"}
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
export declare enum ExtraDataMode {
|
|
2
|
+
REPLACE = "replace",
|
|
3
|
+
MERGE = "merge",
|
|
4
|
+
CLEAR = "clear"
|
|
5
|
+
}
|
|
1
6
|
export interface ScanSegment {
|
|
2
7
|
startFrequency: number;
|
|
3
8
|
stopFrequency: number;
|
|
@@ -53,6 +58,7 @@ export interface SpectrumData {
|
|
|
53
58
|
templateData: Float32Array;
|
|
54
59
|
backgroundNoiseData?: Float32Array;
|
|
55
60
|
waterfallData?: TimestampedFloat32Array[];
|
|
61
|
+
extraData?: Record<string, Float32Array>;
|
|
56
62
|
}
|
|
57
63
|
export interface SpectrumOutputData extends SpectrumData {
|
|
58
64
|
srcIndexCache: Uint32Array;
|
|
@@ -61,6 +67,7 @@ export interface SpectrumOutputData extends SpectrumData {
|
|
|
61
67
|
templateOverData?: TemplateOverData[];
|
|
62
68
|
fluorescenceData?: Map<number, number>[];
|
|
63
69
|
fluorescenceMaxCount?: number;
|
|
70
|
+
extraData?: Record<string, Float32Array>;
|
|
64
71
|
}
|
|
65
72
|
export interface TemplateOverData {
|
|
66
73
|
maxValue: number;
|
|
@@ -70,4 +77,11 @@ export interface TemplateOverData {
|
|
|
70
77
|
startIndex: number;
|
|
71
78
|
endIndex: number;
|
|
72
79
|
}
|
|
80
|
+
export interface ISpectrumAnalyzer {
|
|
81
|
+
readonly config: Required<Omit<SpectrumConfig, 'segments' | 'bandwidthConfig' | 'onSpectrumUpdate'>>;
|
|
82
|
+
readonly extraData: Record<string, Float32Array>;
|
|
83
|
+
readonly antennaFactorData: Float32Array;
|
|
84
|
+
readonly antennaFactorSwitch: boolean;
|
|
85
|
+
readonly srcIndexCache: Uint32Array;
|
|
86
|
+
}
|
|
73
87
|
//# sourceMappingURL=types.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/core/SpectrumAnalyzer/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,WAAW;IAC1B,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,YAAY,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,eAAe,EAAE,OAAO,CAAC;IAClC,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;IAChC,QAAQ,CAAC,kBAAkB,EAAE,OAAO,CAAC;CACtC;AAED,MAAM,WAAW,cAAc;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,UAAU,CAAC,EAAE,OAAO,CAAC,gBAAgB,CAAC,CAAC;IACvC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE;QACZ,KAAK,EAAE,MAAM,CAAC;QACd,GAAG,EAAE,MAAM,CAAC;KACb,CAAC;IACF,QAAQ,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAC9B,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,gBAAgB,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,CAAC,kBAAkB,CAAC,KAAK,IAAI,CAAC;CAChE;AAED,MAAM,WAAW,gBAAgB;IAC/B,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,MAAM,mBAAmB,GAAG,YAAY,GAAG;IAAE,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC;AACxE,MAAM,MAAM,uBAAuB,GAAG,mBAAmB,GAAG;IAC1D,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,uBAAuB,CAAC;IAClC,OAAO,EAAE,YAAY,CAAC;IACtB,OAAO,EAAE,YAAY,CAAC;IACtB,OAAO,EAAE,YAAY,CAAC;IACtB,YAAY,EAAE,YAAY,CAAC;IAC3B,mBAAmB,CAAC,EAAE,YAAY,CAAC;IACnC,aAAa,CAAC,EAAE,uBAAuB,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/core/SpectrumAnalyzer/types.ts"],"names":[],"mappings":"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"}
|
package/index.d.ts
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import LevelStreamAnalyzer from './core/LevelStreamAnalyzer';
|
|
2
2
|
import SpectrumAnalyzer from './core/SpectrumAnalyzer';
|
|
3
3
|
export type { LevelStreamConfig, LevelStreamOutputData } from './core/LevelStreamAnalyzer/types';
|
|
4
|
+
export type { SeriesChangeCallback, SeriesConfig, SeriesEventData, SeriesSubscriber, SubscriptionOptions } from './core/SeriesManager/types';
|
|
5
|
+
export { GraphicType, OrientationType, SeriesEventType } from './core/SeriesManager/types';
|
|
4
6
|
export { ERROR_MESSAGES, SPECTRUM } from './core/SpectrumAnalyzer/constants';
|
|
5
7
|
export { DataValidationError, IndexOutOfBoundsError, SpectrumError } from './core/SpectrumAnalyzer/errors';
|
|
6
8
|
export type { BandwidthConfig, FrequencySegment, ProcessInput, ProcessingConfig, ScanSegment, SpectrumConfig, SpectrumData, SpectrumOutputData, TemplateOverData, TimestampedFloat32Array } from './core/SpectrumAnalyzer/types';
|
|
7
9
|
export { SpectrumAnalyzer, LevelStreamAnalyzer };
|
|
10
|
+
export { default as SeriesManager } from './core/SeriesManager';
|
|
8
11
|
//# sourceMappingURL=index.d.ts.map
|
package/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,mBAAmB,MAAM,4BAA4B,CAAC;AAC7D,OAAO,gBAAgB,MAAM,yBAAyB,CAAC;AAEvD,YAAY,EACV,iBAAiB,EACjB,qBAAqB,EACtB,MAAM,kCAAkC,CAAC;AAE1C,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,mCAAmC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,mBAAmB,MAAM,4BAA4B,CAAC;AAC7D,OAAO,gBAAgB,MAAM,yBAAyB,CAAC;AAEvD,YAAY,EACV,iBAAiB,EACjB,qBAAqB,EACtB,MAAM,kCAAkC,CAAC;AAE1C,YAAY,EACV,oBAAoB,EACpB,YAAY,EACZ,eAAe,EACf,gBAAgB,EAChB,mBAAmB,EACpB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,WAAW,EACX,eAAe,EACf,eAAe,EAChB,MAAM,4BAA4B,CAAC;AAEpC,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,mCAAmC,CAAC;AAE7E,OAAO,EACL,mBAAmB,EACnB,qBAAqB,EACrB,aAAa,EACd,MAAM,gCAAgC,CAAC;AAExC,YAAY,EACV,eAAe,EACf,gBAAgB,EAChB,YAAY,EACZ,gBAAgB,EAChB,WAAW,EACX,cAAc,EACd,YAAY,EACZ,kBAAkB,EAClB,gBAAgB,EAChB,uBAAuB,EACxB,MAAM,+BAA+B,CAAC;AAGvC,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,CAAC;AACjD,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,sBAAsB,CAAC"}
|
package/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
const LEVEL_STREAM={DEFAULT_CACHE_TIME:15e3,DEFAULT_GRANULARITY:10,DEFAULT_RANGE:[-20,100]};const DEFAULT_LEVEL_STREAM_CONFIG={cacheTime:LEVEL_STREAM.DEFAULT_CACHE_TIME,granularity:LEVEL_STREAM.DEFAULT_GRANULARITY,range:LEVEL_STREAM.DEFAULT_RANGE,onLevelStreamUpdate:data=>{}};class LevelStreamAnalyzer{config;spectrumData=[];probabilityData=new Map;count=0;constructor(config){this.config={...DEFAULT_LEVEL_STREAM_CONFIG,...config}}reset(){this.spectrumData=[];this.probabilityData=new Map;this.count=0}setConfig(config){this.config={...DEFAULT_LEVEL_STREAM_CONFIG,...this.config,...config};if(config.cacheTime&&this.config.cacheTime!==config.cacheTime||config.granularity&&this.config.granularity!==config.granularity)this.reset();if(config.range)this.outputData()}process(level){this.removeExpiredData();this.addNewData(level);this.updateProbability(level);this.outputData()}updateProbability(level){const{granularity}=this.config;this.count++;const bin=Math.round(level/granularity)*granularity;let binCount=this.probabilityData.get(bin)||0;binCount++;this.probabilityData.set(bin,binCount)}getAll(){return this.probabilityData}removeExpiredData(){const now=Date.now();const{cacheTime}=this.config;if(cacheTime<=0){this.spectrumData=[];return}if(0===this.spectrumData.length)return;let left=0;let right=this.spectrumData.length-1;while(left<=right){const mid=Math.floor((left+right)/2);if(now-this.spectrumData[mid].timestamp>=cacheTime)left=mid+1;else right=mid-1}this.spectrumData=this.spectrumData.slice(left)}addNewData(level){const now=Date.now();this.spectrumData.push({value:level,timestamp:now})}outputData(){const{range,granularity,onLevelStreamUpdate}=this.config;const rangeMin=range[0];const rangeMax=range[1];const probabilityRangeData=new Array(Math.round((rangeMax-rangeMin)/granularity)+1).fill(0);for(const[bin,count]of this.probabilityData)if(bin>=rangeMin&&bin<=rangeMax){const index=Math.round((rangeMax-bin)/granularity);if(this.count>0)probabilityRangeData[index]=count/this.count*100}onLevelStreamUpdate?.({probabilityRangeData:new Float32Array(probabilityRangeData),spectrumData:new Float32Array(this.spectrumData.map(item=>item.value))})}}const SPECTRUM={INITIAL_VALUE:Number.NaN,WATERFALL_MAX_FRAMES:100,OUTPUT_POINTS:1001};const DEFAULT_SPECTRUM_CONFIG={maxPoints:SPECTRUM.OUTPUT_POINTS,waterfallMaxFrames:SPECTRUM.WATERFALL_MAX_FRAMES,initialValue:SPECTRUM.INITIAL_VALUE,processing:{enableWaterfall:false,enableMetrics:false,enableFluorescence:false},outputPoints:SPECTRUM.OUTPUT_POINTS,outputRange:{start:0,end:SPECTRUM.OUTPUT_POINTS}};const ERROR_MESSAGES={EMPTY_SEGMENTS:"频段配置不能为空",INVALID_CONFIG:"必须且只能配置 segments 或 bandwidthConfig 其中之一",EMPTY_BANDWIDTH:"bandwidthConfig 不能为空",INVALID_SEGMENT:index=>`无效的段索引: ${index}`,INDEX_OUT_OF_BOUNDS:index=>`索引超出范围: ${index}`,INVALID_ANTENNA_FACTOR_LENGTH:points=>`天线因子数据长度必须等于实时数据长度 (${points})`,INVALID_ANTENNA_FACTOR:"天线因子数据必须是有效的正数",INVALID_SAMPLING_RANGE:"采样范围无效",INVALID_MAX_POINTS:"点数必须大于0",INVALID_LENGTH:expected=>`频率占用度数据长度不匹配,期望长度为 ${expected}`};class SpectrumError extends Error{code;details;constructor(message,code,details){super(message),this.code=code,this.details=details;this.name="SpectrumError"}}class DataValidationError extends SpectrumError{constructor(message,details){super(message,"DATA_VALIDATION_ERROR",details)}}class IndexOutOfBoundsError extends SpectrumError{index;constructor(message,index,details){super(message,"INDEX_OUT_OF_BOUNDS_ERROR",{index,...details||{}}),this.index=index}}const arrayKeepAttribute=(source,target)=>{if(void 0!==source.max)target.max=source.max;if(void 0!==source.maxIndex)target.maxIndex=source.maxIndex;if(void 0!==source.timestamp)target.timestamp=source.timestamp;if(void 0!==source.progress)target.progress=source.progress};const resample=({realData,antennaFactorData,antennaFactorSwitch=false,outputPoints})=>{const realDataLength=realData.length;const isLessThanDataLength=realDataLength<=outputPoints;const outputLength=isLessThanDataLength?realDataLength:outputPoints;const srcIndexCache=new Uint32Array(outputLength);const realOutputData=new Float32Array(outputLength);realOutputData.timestamp=realData.timestamp;if(isLessThanDataLength){if(!antennaFactorSwitch){for(let i=0;i<realDataLength;i++)srcIndexCache[i]=i;realOutputData.set(realData);return{realOutputData,srcIndexCache}}for(let i=0;i<realDataLength;i++){srcIndexCache[i]=i;realOutputData[i]=realData[i]+antennaFactorData[i]}return{realOutputData,srcIndexCache}}const ratio=realDataLength/outputPoints;let pos=ratio/2;for(let i=0;i<outputLength;i++){const start=Math.floor(pos);const end=Math.min(Math.floor(pos+ratio),realDataLength);let maxValue=realData[start];let maxIndex=start;for(let j=start+1;j<end;j++)if(realData[j]>maxValue){maxValue=realData[j];maxIndex=j}realOutputData[i]=antennaFactorSwitch?maxValue+antennaFactorData[maxIndex]:maxValue;srcIndexCache[i]=maxIndex;pos+=ratio}return{realOutputData,srcIndexCache}};const resampleMultiple=({antennaFactorData,antennaFactorSwitch=false,outputPoints,realData,maxData,minData,avgData,templateData,backgroundNoiseData,fluorescenceData})=>{const realDataLength=realData.length;const isLessThanDataLength=realDataLength<=outputPoints;const outputLength=isLessThanDataLength?realDataLength:outputPoints;const hasMaxData=maxData&&maxData.length>0;const hasMinData=minData&&minData.length>0;const hasAvgData=avgData&&avgData.length>0;const hasTemplateData=templateData&&templateData.length>0;const hasBackgroundNoiseData=backgroundNoiseData&&backgroundNoiseData.length>0;const hasFluorescenceStats=fluorescenceData&&fluorescenceData.length>0;const applyAntennaFactor=antennaFactorSwitch?(value,index)=>value+antennaFactorData[index]:value=>value;const realOutputData=new Float32Array(outputLength);realOutputData.timestamp=realData.timestamp;const maxOutputData=new Float32Array(hasMaxData?outputLength:0);const minOutputData=new Float32Array(hasMinData?outputLength:0);const avgOutputData=new Float32Array(hasAvgData?outputLength:0);const templateOutputData=new Float32Array(hasTemplateData?outputLength:0);const backgroundNoiseOutputData=new Float32Array(hasBackgroundNoiseData?outputLength:0);let fluorescenceOutputData=new Array(hasFluorescenceStats?outputLength:0).fill(null);const srcIndexCache=new Uint32Array(outputLength);if(isLessThanDataLength){for(let i=0;i<realDataLength;i++)srcIndexCache[i]=i;if(antennaFactorSwitch)for(let i=0;i<realDataLength;i++){const antennaFactor=antennaFactorData[i];realOutputData[i]=realData[i]+antennaFactor;if(hasMaxData)maxOutputData[i]=maxData[i]+antennaFactor;if(hasMinData)minOutputData[i]=minData[i]+antennaFactor;if(hasAvgData)avgOutputData[i]=avgData[i]+antennaFactor;if(hasTemplateData)templateOutputData[i]=templateData[i]+antennaFactor;if(hasBackgroundNoiseData)backgroundNoiseOutputData[i]=backgroundNoiseData[i]+antennaFactor;if(hasFluorescenceStats){const fluorescence=fluorescenceData[i];const newFluorescence=new Map;for(const[key,value]of fluorescence)newFluorescence.set(key+antennaFactor,value);fluorescenceOutputData[i]=newFluorescence}}else{realOutputData.set(realData);if(hasMaxData)maxOutputData.set(maxData);if(hasMinData)minOutputData.set(minData);if(hasAvgData)avgOutputData.set(avgData);if(hasTemplateData)templateOutputData.set(templateData);if(hasBackgroundNoiseData)backgroundNoiseOutputData.set(backgroundNoiseData);if(hasFluorescenceStats)fluorescenceOutputData=fluorescenceData}}else{const ratio=realDataLength/outputPoints;let pos=ratio/2;for(let i=0;i<outputLength;i++){const start=Math.floor(pos);const end=Math.min(Math.floor(pos+ratio),realDataLength);let realMaxVal=realData[start];let realMaxIdx=start;let maxVal=hasMaxData?maxData[start]:0;let maxIdx=start;let minVal=hasMinData?minData[start]:0;let minIdx=start;for(let j=start+1;j<end;j++){if(realData[j]>realMaxVal){realMaxVal=realData[j];realMaxIdx=j}if(hasMaxData&&maxData[j]>maxVal){maxVal=maxData[j];maxIdx=j}if(hasMinData&&minData[j]<minVal){minVal=minData[j];minIdx=j}}realOutputData[i]=applyAntennaFactor(realMaxVal,realMaxIdx);srcIndexCache[i]=realMaxIdx;if(hasMaxData)maxOutputData[i]=applyAntennaFactor(maxVal,maxIdx);if(hasMinData)minOutputData[i]=applyAntennaFactor(minVal,minIdx);if(hasAvgData){const avgValue=avgData[realMaxIdx];avgOutputData[i]=applyAntennaFactor(avgValue,realMaxIdx)}if(hasTemplateData){const templateValue=templateData[realMaxIdx];templateOutputData[i]=applyAntennaFactor(templateValue,realMaxIdx)}if(hasBackgroundNoiseData){const backgroundNoiseValue=backgroundNoiseData[realMaxIdx];backgroundNoiseOutputData[i]=applyAntennaFactor(backgroundNoiseValue,realMaxIdx)}if(hasFluorescenceStats){const fluorescence=fluorescenceData[realMaxIdx];const newFluorescence=new Map;for(const[key,value]of fluorescence)newFluorescence.set(applyAntennaFactor(key,realMaxIdx),value);fluorescenceOutputData[i]=newFluorescence}pos+=ratio}}return{realOutputData,maxOutputData,minOutputData,avgOutputData,templateOutputData,backgroundNoiseOutputData,srcIndexCache,fluorescenceOutputData}};const findExceedingDatasCore=({realData,maxData,minData,templateData,startIndex=0,endIndex,usePreallocation=false})=>{const{timestamp}=realData;const actualEndIndex=endIndex??realData.length;const segments=[];let start=-1;let sum=0;let count=0;if(usePreallocation&&0===startIndex&&actualEndIndex===realData.length){const exceedingFlags=new Uint8Array(realData.length);for(let i=0;i<realData.length;i++)exceedingFlags[i]=realData[i]>templateData[i]?1:0;for(let i=0;i<realData.length;i++)if(exceedingFlags[i]){if(-1===start){start=i;sum=realData[i];count=1}else{sum+=realData[i];count++}}else if(-1!==start){const end=i-1;if(end-start+1>=2){const avgValue=sum/count;const middleIndex=start+(end-start>>1);segments.push({maxValue:maxData[middleIndex],minValue:minData[middleIndex],avgValue,timestamp,startIndex:start,endIndex:end})}start=-1}}else for(let i=startIndex;i<Math.min(actualEndIndex,realData.length);i++){const isExceeding=realData[i]>templateData[i];if(isExceeding){if(-1===start){start=i;sum=realData[i];count=1}else{sum+=realData[i];count++}}else if(-1!==start){const end=i-1;if(end-start+1>=2){const avgValue=sum/count;const middleIndex=start+(end-start>>1);segments.push({maxValue:maxData[middleIndex],minValue:minData[middleIndex],avgValue,timestamp,startIndex:start,endIndex:end})}start=-1}}if(-1!==start){const end=actualEndIndex-1;if(end-start+1>=2){const avgValue=sum/count;const middleIndex=start+(end-start>>1);segments.push({maxValue:maxData[middleIndex],minValue:minData[middleIndex],avgValue,timestamp,startIndex:start,endIndex:end})}}return segments};const findExceedingDatas=({realData,maxData,minData,templateData})=>{if(!templateData||0===templateData.length)return[];return findExceedingDatasCore({realData,maxData,minData,templateData,usePreallocation:true})};const findExceedingDatasIncremental=({realData,maxData,minData,templateData,startIndex,endIndex,previousSegments=[]})=>{if(!templateData||0===templateData.length||startIndex>=endIndex)return previousSegments;const newSegments=findExceedingDatasCore({realData,maxData,minData,templateData,startIndex,endIndex});return[...previousSegments,...newSegments]};class SpectrumAnalyzer{config=DEFAULT_SPECTRUM_CONFIG;segments=[];antennaFactorData;antennaFactorSwitch;realData;maxData;minData;avgData;templateData;backgroundNoiseData;waterfallData;srcIndexCache;realOutputData;waterfallOutputData;scanProgress;lastIndex;processTimes;lastProcessTime;cachedExceedingDatas=[];fluorescenceData;fluorescenceMaxCount=0;onSpectrumUpdate;constructor(config){const{onSpectrumUpdate,maxPoints}=config;this.onSpectrumUpdate=onSpectrumUpdate;this.config={...DEFAULT_SPECTRUM_CONFIG,...config,processing:{...DEFAULT_SPECTRUM_CONFIG.processing,...config.processing},outputRange:{start:config.outputRange?.start??0,end:config.outputRange?.end??maxPoints??SPECTRUM.OUTPUT_POINTS}};this.reset()}process({data,timestamp,segmentOffset=0,offset=0}){const processStartTime=performance.now();try{if(!data?.length)return;let index=offset;if(this.segments.length){const segment=this.segments[segmentOffset];if(!segment)throw new DataValidationError(ERROR_MESSAGES.INVALID_SEGMENT(segmentOffset));index=segment.startIndex+offset;this.scanProgress=(index+data.length)/this.config.maxPoints}else if(data.length!==this.config.maxPoints)this.updateMaxPoints(data.length);this.validateInput(data,index);const{maxPoints}=this.config;const endIndex=index+data.length;this.lastIndex=endIndex;const isOver=endIndex>=maxPoints||endIndex<this.lastIndex;this.realData.set(data,index);this.realData.timestamp=timestamp;this.processDataPoints(data,index,isOver);const processedData=this.resampleDataSeries();if(isOver)this.updateWaterfallData(this.realData,processedData.realData);const templateOverData=this.updateTemplateOverData(isOver,isOver?void 0:{startIndex:index,endIndex:index+data.length});this.notifySpectrumUpdate({...processedData,waterfallData:this.waterfallOutputData,scanProgress:this.scanProgress,processTimes:this.processTimes,...templateOverData&&{templateOverData}})}catch(error){throw error instanceof Error?error:new Error(String(error))}finally{this.lastProcessTime=performance.now()-processStartTime}}initializeSegments(segments){if(!segments?.length)throw new DataValidationError(ERROR_MESSAGES.EMPTY_SEGMENTS);let totalPoints=0;this.segments=segments.map(segment=>{const{startFrequency,stopFrequency,stepFrequency}=segment;const frequencyRange=stopFrequency-startFrequency;const stepCount=1e3*frequencyRange/stepFrequency;const pointCount=Math.round(stepCount)+1;const startIndex=totalPoints;totalPoints+=pointCount;return{startFrequency,stopFrequency,stepFrequency,pointCount,startIndex}});this.updateMaxPoints(totalPoints)}setAntennaFactor(d){const{antennaFactorData,config:{maxPoints}}=this;let data=new Float32Array(d);if(data.length!==maxPoints){data=new Float32Array(data).subarray(0,maxPoints);console.warn(ERROR_MESSAGES.INVALID_ANTENNA_FACTOR_LENGTH(maxPoints))}let hasInvalid=false;for(let i=0;i<data.length;i++){const value=data[i];const isNiceFinite=Number.isFinite(value)&&value>0;if(!isNiceFinite)hasInvalid=true;antennaFactorData[i]=isNiceFinite?value:0}if(hasInvalid)console.warn(ERROR_MESSAGES.INVALID_ANTENNA_FACTOR);if(this.antennaFactorSwitch)this.setAntennaFactorSwitch(this.antennaFactorSwitch)}setAntennaFactorSwitch(newAntennaFactorSwitch){const isChange=this.antennaFactorSwitch!==newAntennaFactorSwitch;this.antennaFactorSwitch=newAntennaFactorSwitch;if(isChange){const processedData=this.resampleDataSeries();this.resampleWaterfallOutputData();this.notifySpectrumUpdate({...processedData,waterfallData:this.waterfallOutputData})}}setWaterfallData(newWaterfallData){if(!(newWaterfallData?.[0]?.length>0))return;const{processing}=this.config;let{waterfallMaxFrames}=this.config;if(!processing.enableWaterfall)return;waterfallMaxFrames=newWaterfallData.length;this.config={...this.config,waterfallMaxFrames};this.waterfallData=newWaterfallData;this.resampleWaterfallOutputData();this.notifySpectrumUpdate({waterfallData:this.waterfallOutputData})}setRealData(data){if(!(data?.length>0)||data.length!==this.config.maxPoints)return;const newData=new Float32Array(data.length);newData.set(data);newData.timestamp=data.timestamp;this.realData=newData;const processedData=this.resampleDataSeries();this.notifySpectrumUpdate(processedData)}setMaxData(data){if(!(data?.length>0)||data.length!==this.config.maxPoints)return;const newData=new Float32Array(data.length);newData.set(data);this.maxData=newData;this.maxData.allValid=this.isAllValid(this.maxData);const processedData=this.resampleDataSeries();this.notifySpectrumUpdate(processedData)}setMinData(data){if(!(data?.length>0)||data.length!==this.config.maxPoints)return;const newData=new Float32Array(data.length);newData.set(data);this.minData=newData;this.minData.allValid=this.isAllValid(this.minData);const processedData=this.resampleDataSeries();this.notifySpectrumUpdate(processedData)}setAvgData(data){if(!(data?.length>0)||data.length!==this.config.maxPoints)return;const newData=new Float32Array(data.length);newData.set(data);this.avgData=newData;this.avgData.allValid=this.isAllValid(this.avgData);const processedData=this.resampleDataSeries();this.notifySpectrumUpdate(processedData)}reset(){const{maxPoints,waterfallMaxFrames,processing:{enableMetrics,enableFluorescence}}=this.config;this.antennaFactorData=new Float32Array(maxPoints);const realData=new Float32Array(maxPoints);realData.timestamp=0;realData.fill(SPECTRUM.INITIAL_VALUE);this.realData=realData;this.maxData=new Float32Array(enableMetrics?maxPoints:0).fill(SPECTRUM.INITIAL_VALUE);this.minData=new Float32Array(enableMetrics?maxPoints:0).fill(SPECTRUM.INITIAL_VALUE);this.avgData=new Float32Array(enableMetrics?maxPoints:0).fill(SPECTRUM.INITIAL_VALUE);this.templateData=new Float32Array;this.backgroundNoiseData=new Float32Array;this.waterfallData=Array.from({length:waterfallMaxFrames},()=>{const frame=new Float32Array;frame.timestamp=0;frame.fill(SPECTRUM.INITIAL_VALUE);return frame});this.waterfallOutputData=Array.from({length:waterfallMaxFrames},()=>{const frame=new Float32Array;frame.timestamp=0;frame.fill(SPECTRUM.INITIAL_VALUE);return frame});this.fluorescenceData=enableFluorescence?Array.from({length:maxPoints},()=>new Map):[];this.fluorescenceMaxCount=0;this.srcIndexCache=new Uint32Array(maxPoints);this.scanProgress=0;this.lastIndex=0;this.processTimes=0;this.lastProcessTime=0;this.cachedExceedingDatas=[];this.notifySpectrumUpdate({realData:this.realData,maxData:this.maxData,minData:this.minData,avgData:this.avgData,templateData:this.templateData,backgroundNoiseData:this.backgroundNoiseData,srcIndexCache:this.srcIndexCache,processTimes:0,scanProgress:0})}getData(){const{realData,maxData,minData,avgData,templateData,backgroundNoiseData,fluorescenceData,fluorescenceMaxCount,srcIndexCache,waterfallData,processTimes}=this;return{realData,maxData,minData,avgData,templateData,backgroundNoiseData,srcIndexCache,waterfallData,processTimes,fluorescenceData,fluorescenceMaxCount}}getPerformanceMetrics(){return{lastProcessTime:this.lastProcessTime,dataPoints:this.config.maxPoints,waterfallFrames:this.waterfallData.length,isInitialized:this.realData.length>0,memoryUsage:this.calculateMemoryUsage()}}updateSamplingRange(start,end){if(start<0||start>=end)throw new DataValidationError(ERROR_MESSAGES.INVALID_SAMPLING_RANGE);this.config={...this.config,outputRange:{start:Math.floor(start),end:Math.ceil(end)}};const processedData=this.resampleDataSeries();this.resampleWaterfallOutputData();this.notifySpectrumUpdate({...processedData,waterfallData:this.waterfallOutputData});return this.srcIndexCache}setTemplateData(data){if(!data||0===data.length){this.templateData=new Float32Array(0);return}this.templateData=new Float32Array(data);if(0===this.processTimes||!this.srcIndexCache||0===this.srcIndexCache.length)return;const{srcIndexCache,config:{outputPoints}}=this;const templateOutputData=new Float32Array(outputPoints);for(let i=0;i<outputPoints;i++)templateOutputData[i]=this.templateData[srcIndexCache[i]];const templateOverData=this.updateTemplateOverData(true);this.notifySpectrumUpdate({templateData:templateOutputData,templateOverData})}setBackgroundNoiseData(data){if(!data||0===data.length){this.backgroundNoiseData=new Float32Array(0);return}this.backgroundNoiseData=new Float32Array(data);const{srcIndexCache,config:{outputPoints}}=this;const backgroundNoiseOutputData=new Float32Array(outputPoints);for(let i=0;i<outputPoints;i++)backgroundNoiseOutputData[i]=this.backgroundNoiseData[srcIndexCache[i]];this.notifySpectrumUpdate({backgroundNoiseData:backgroundNoiseOutputData})}updateTemplateOverData(forceFullCalculation=false,incrementalRange){if(!this.templateData||0===this.templateData.length){this.cachedExceedingDatas=[];return[]}let templateOverData;if(forceFullCalculation||!incrementalRange){templateOverData=findExceedingDatas({realData:this.realData,maxData:this.maxData,minData:this.minData,templateData:this.templateData});this.cachedExceedingDatas=templateOverData}else{this.cachedExceedingDatas=findExceedingDatasIncremental({realData:this.realData,maxData:this.maxData,minData:this.minData,templateData:this.templateData,startIndex:incrementalRange.startIndex,endIndex:incrementalRange.endIndex,previousSegments:this.cachedExceedingDatas});templateOverData=this.cachedExceedingDatas}return templateOverData}resampleDataSeries(){const{antennaFactorData,antennaFactorSwitch,maxData,minData,avgData,templateData,backgroundNoiseData,config:{maxPoints,outputPoints}}=this;const activeAntennaFactorData=antennaFactorSwitch?antennaFactorData:new Float32Array(maxPoints);const{realOutputData,srcIndexCache,maxOutputData,minOutputData,avgOutputData,templateOutputData,backgroundNoiseOutputData}=resampleMultiple({antennaFactorData:activeAntennaFactorData,antennaFactorSwitch,outputPoints,realData:this.getOutputData(),maxData:maxData&&maxData.length>0?this.getOutputData(maxData):void 0,minData:minData&&minData.length>0?this.getOutputData(minData):void 0,avgData:avgData&&avgData.length>0?this.getOutputData(avgData):void 0,templateData:templateData&&templateData.length>0?this.getOutputData(templateData):void 0,backgroundNoiseData:backgroundNoiseData&&backgroundNoiseData.length>0?this.getOutputData(backgroundNoiseData):void 0});this.srcIndexCache=srcIndexCache;return{realData:realOutputData,maxData:maxOutputData,minData:minOutputData,avgData:avgOutputData,templateData:templateOutputData,backgroundNoiseData:backgroundNoiseOutputData,fluorescenceData:this.getFluorescenceOutputData(),fluorescenceMaxCount:this.fluorescenceMaxCount,srcIndexCache}}resampleWaterfallOutputData(){const{antennaFactorData,antennaFactorSwitch,waterfallData,config:{maxPoints,processing:{enableWaterfall},outputPoints}}=this;if(!enableWaterfall)return;const activeAntennaFactorData=antennaFactorSwitch?antennaFactorData:new Float32Array(maxPoints);this.waterfallOutputData=waterfallData.map(frame=>{const realData=this.getOutputData(frame);const{realOutputData}=resampleMultiple({realData,antennaFactorData:activeAntennaFactorData,antennaFactorSwitch,outputPoints});return realOutputData})}updateWaterfallData(data,outputData){const{waterfallMaxFrames,processing}=this.config;if(!processing.enableWaterfall)return;if(this.waterfallData.length>=waterfallMaxFrames){this.waterfallData.shift();this.waterfallOutputData.shift()}const newData=new Float32Array(data.length);newData.set(data);newData.timestamp=data.timestamp;this.waterfallData.push(newData);this.waterfallOutputData.push(outputData)}updateMaxPoints(maxPoints){if(this.config.maxPoints===maxPoints)return;this.config={...this.config,maxPoints,outputRange:{start:0,end:maxPoints}};this.reset()}validateInput(data,index){if(index<0||index+data.length>this.config.maxPoints)throw new IndexOutOfBoundsError(ERROR_MESSAGES.INDEX_OUT_OF_BOUNDS(index),index)}processDataPoints(data,index,isOver){const{maxData,minData,avgData,config:{processing:{enableMetrics}}}=this;if(!enableMetrics)return;if(isOver){this.processTimes+=1;if(!maxData.allValid)maxData.allValid=this.isAllValid(maxData);if(!minData.allValid)minData.allValid=this.isAllValid(minData);if(!avgData.allValid)avgData.allValid=this.isAllValid(avgData)}let allValid=true;const length=data.length;for(let i=0;i<length;i++)if(!Number.isFinite(data[i])){allValid=false;break}for(let i=0;i<length;i++){const dataIndex=index+i;const value=data[i];if(!allValid&&!Number.isFinite(value))continue;const oldMax=maxData[dataIndex];if(value>oldMax||!maxData.allValid&&Number.isNaN(oldMax))maxData[dataIndex]=value;const oldMin=minData[dataIndex];if(value<oldMin||!minData.allValid&&Number.isNaN(oldMin))minData[dataIndex]=value;const oldAvg=avgData[dataIndex];if(0===this.processTimes||Number.isNaN(oldAvg))avgData[dataIndex]=value;else avgData[dataIndex]=oldAvg+(value-oldAvg)/(this.processTimes+1);this.updateFluorescenceStats(dataIndex,value)}}updateFluorescenceStats(dataIndex,value){const{processing}=this.config;if(!processing.enableFluorescence||!this.fluorescenceData)return;if(!Number.isFinite(value))return;const level=Math.round(value);let levelMap=this.fluorescenceData[dataIndex];if(!levelMap){levelMap=new Map;this.fluorescenceData[dataIndex]=levelMap}const currentCount=levelMap.get(level)??0;const newCount=currentCount+1;levelMap.set(level,newCount);if(newCount>this.fluorescenceMaxCount)this.fluorescenceMaxCount=newCount}isAllValid(arr){for(let i=0;i<arr.length;i++)if(!Number.isFinite(arr[i]))return false;return true}notifySpectrumUpdate(processedData){this.onSpectrumUpdate?.(processedData)}calculateMemoryUsage(){const arraySize=this.config.maxPoints*Float32Array.BYTES_PER_ELEMENT;const baseArrayMemory=4*arraySize;const rawWaterfallMemory=this.waterfallData.reduce((sum,frame)=>sum+frame.length*Float32Array.BYTES_PER_ELEMENT,0);const outputWaterfallMemory=this.waterfallOutputData.reduce((sum,frame)=>sum+frame.length*Float32Array.BYTES_PER_ELEMENT,0);return baseArrayMemory+rawWaterfallMemory+outputWaterfallMemory}getOutputData(data){const{outputRange:{start,end}}=this.config;const sourceData=data??this.realData;const outputData=sourceData.subarray(start,end);outputData.timestamp=sourceData.timestamp;return outputData}getFluorescenceOutputData(data){const{outputRange:{start,end}}=this.config;const sourceData=data??this.fluorescenceData;if(!sourceData||0===sourceData.length)return;return sourceData.slice(start,end)}getAllRawData(){const{realData,maxData,minData,avgData,templateData,backgroundNoiseData,waterfallData}=this;return{realData,maxData,minData,avgData,templateData,backgroundNoiseData,waterfallData}}}export{DataValidationError,ERROR_MESSAGES,IndexOutOfBoundsError,LevelStreamAnalyzer,SPECTRUM,SpectrumAnalyzer,SpectrumError};
|
|
1
|
+
const LEVEL_STREAM={DEFAULT_CACHE_TIME:15e3,DEFAULT_GRANULARITY:10,DEFAULT_RANGE:[-20,100]};const DEFAULT_LEVEL_STREAM_CONFIG={cacheTime:LEVEL_STREAM.DEFAULT_CACHE_TIME,granularity:LEVEL_STREAM.DEFAULT_GRANULARITY,range:LEVEL_STREAM.DEFAULT_RANGE,onLevelStreamUpdate:data=>{}};class LevelStreamAnalyzer{config;spectrumData=[];probabilityData=new Map;count=0;constructor(config){this.config={...DEFAULT_LEVEL_STREAM_CONFIG,...config}}reset(){this.spectrumData=[];this.probabilityData=new Map;this.count=0}setConfig(config){this.config={...DEFAULT_LEVEL_STREAM_CONFIG,...this.config,...config};if(config.cacheTime&&this.config.cacheTime!==config.cacheTime||config.granularity&&this.config.granularity!==config.granularity)this.reset();if(config.range)this.outputData()}process(level,timestamp){this.removeExpiredData();this.addNewData(level,timestamp);this.updateProbability(level);this.outputData()}updateProbability(level){const{granularity}=this.config;this.count++;const bin=Math.round(level/granularity)*granularity;let binCount=this.probabilityData.get(bin)||0;binCount++;this.probabilityData.set(bin,binCount)}getAll(){return this.probabilityData}removeExpiredData(){const now=Date.now();const{cacheTime}=this.config;if(cacheTime<=0){this.spectrumData=[];return}if(0===this.spectrumData.length)return;let left=0;let right=this.spectrumData.length-1;while(left<=right){const mid=Math.floor((left+right)/2);if(now-this.spectrumData[mid].timestamp>=cacheTime)left=mid+1;else right=mid-1}this.spectrumData=this.spectrumData.slice(left)}addNewData(level,timestamp){this.spectrumData.push({value:level,timestamp})}outputData(){const{range,granularity,onLevelStreamUpdate}=this.config;const rangeMin=range[0];const rangeMax=range[1];const probabilityRangeData=new Array(Math.round((rangeMax-rangeMin)/granularity)+1).fill(0);for(const[bin,count]of this.probabilityData)if(bin>=rangeMin&&bin<=rangeMax){const index=Math.round((rangeMax-bin)/granularity);if(this.count>0)probabilityRangeData[index]=count/this.count*100}onLevelStreamUpdate?.({probabilityRangeData:new Float32Array(probabilityRangeData),spectrumData:new Float32Array(this.spectrumData.map(item=>item.value)),timestampData:new Float32Array(this.spectrumData.map(item=>item.timestamp))})}}const SPECTRUM={INITIAL_VALUE:Number.NaN,WATERFALL_MAX_FRAMES:100,OUTPUT_POINTS:1001};const DEFAULT_SPECTRUM_CONFIG={maxPoints:SPECTRUM.OUTPUT_POINTS,waterfallMaxFrames:SPECTRUM.WATERFALL_MAX_FRAMES,initialValue:SPECTRUM.INITIAL_VALUE,processing:{enableWaterfall:false,enableMetrics:false,enableFluorescence:false},outputPoints:SPECTRUM.OUTPUT_POINTS,outputRange:{start:0,end:SPECTRUM.OUTPUT_POINTS}};const ERROR_MESSAGES={EMPTY_SEGMENTS:"频段配置不能为空",INVALID_CONFIG:"必须且只能配置 segments 或 bandwidthConfig 其中之一",EMPTY_BANDWIDTH:"bandwidthConfig 不能为空",INVALID_SEGMENT:index=>`无效的段索引: ${index}`,INDEX_OUT_OF_BOUNDS:index=>`索引超出范围: ${index}`,INVALID_ANTENNA_FACTOR_LENGTH:points=>`天线因子数据长度必须等于实时数据长度 (${points})`,INVALID_ANTENNA_FACTOR:"天线因子数据必须是有效的正数",INVALID_SAMPLING_RANGE:"采样范围无效",INVALID_MAX_POINTS:"点数必须大于0",INVALID_LENGTH:expected=>`频率占用度数据长度不匹配,期望长度为 ${expected}`};class SpectrumError extends Error{code;details;constructor(message,code,details){super(message),this.code=code,this.details=details;this.name="SpectrumError"}}class DataValidationError extends SpectrumError{constructor(message,details){super(message,"DATA_VALIDATION_ERROR",details)}}class IndexOutOfBoundsError extends SpectrumError{index;constructor(message,index,details){super(message,"INDEX_OUT_OF_BOUNDS_ERROR",{index,...details||{}}),this.index=index}}const arrayKeepAttribute=(source,target)=>{if(void 0!==source.max)target.max=source.max;if(void 0!==source.maxIndex)target.maxIndex=source.maxIndex;if(void 0!==source.timestamp)target.timestamp=source.timestamp;if(void 0!==source.progress)target.progress=source.progress};const resample=({realData,antennaFactorData,antennaFactorSwitch=false,outputPoints})=>{const realDataLength=realData.length;const isLessThanDataLength=realDataLength<=outputPoints;const outputLength=isLessThanDataLength?realDataLength:outputPoints;const srcIndexCache=new Uint32Array(outputLength);const realOutputData=new Float32Array(outputLength);realOutputData.timestamp=realData.timestamp;if(isLessThanDataLength){if(!antennaFactorSwitch){for(let i=0;i<realDataLength;i++)srcIndexCache[i]=i;realOutputData.set(realData);return{realOutputData,srcIndexCache}}for(let i=0;i<realDataLength;i++){srcIndexCache[i]=i;realOutputData[i]=realData[i]+antennaFactorData[i]}return{realOutputData,srcIndexCache}}const ratio=realDataLength/outputPoints;let pos=ratio/2;for(let i=0;i<outputLength;i++){const start=Math.floor(pos);const end=Math.min(Math.floor(pos+ratio),realDataLength);let maxValue=realData[start];let maxIndex=start;for(let j=start+1;j<end;j++)if(realData[j]>maxValue){maxValue=realData[j];maxIndex=j}realOutputData[i]=antennaFactorSwitch?maxValue+antennaFactorData[maxIndex]:maxValue;srcIndexCache[i]=maxIndex;pos+=ratio}return{realOutputData,srcIndexCache}};const resampleMultiple=({antennaFactorData,antennaFactorSwitch=false,outputPoints,realData,maxData,minData,avgData,templateData,backgroundNoiseData,fluorescenceData})=>{const realDataLength=realData.length;const isLessThanDataLength=realDataLength<=outputPoints;const outputLength=isLessThanDataLength?realDataLength:outputPoints;const hasMaxData=maxData&&maxData.length>0;const hasMinData=minData&&minData.length>0;const hasAvgData=avgData&&avgData.length>0;const hasTemplateData=templateData&&templateData.length>0;const hasBackgroundNoiseData=backgroundNoiseData&&backgroundNoiseData.length>0;const hasFluorescenceStats=fluorescenceData&&fluorescenceData.length>0;const applyAntennaFactor=antennaFactorSwitch?(value,index)=>value+antennaFactorData[index]:value=>value;const realOutputData=new Float32Array(outputLength);realOutputData.timestamp=realData.timestamp;const maxOutputData=new Float32Array(hasMaxData?outputLength:0);const minOutputData=new Float32Array(hasMinData?outputLength:0);const avgOutputData=new Float32Array(hasAvgData?outputLength:0);const templateOutputData=new Float32Array(hasTemplateData?outputLength:0);const backgroundNoiseOutputData=new Float32Array(hasBackgroundNoiseData?outputLength:0);let fluorescenceOutputData=new Array(hasFluorescenceStats?outputLength:0).fill(null);const srcIndexCache=new Uint32Array(outputLength);if(isLessThanDataLength){for(let i=0;i<realDataLength;i++)srcIndexCache[i]=i;if(antennaFactorSwitch)for(let i=0;i<realDataLength;i++){const antennaFactor=antennaFactorData[i];realOutputData[i]=realData[i]+antennaFactor;if(hasMaxData)maxOutputData[i]=maxData[i]+antennaFactor;if(hasMinData)minOutputData[i]=minData[i]+antennaFactor;if(hasAvgData)avgOutputData[i]=avgData[i]+antennaFactor;if(hasTemplateData)templateOutputData[i]=templateData[i]+antennaFactor;if(hasBackgroundNoiseData)backgroundNoiseOutputData[i]=backgroundNoiseData[i]+antennaFactor;if(hasFluorescenceStats){const fluorescence=fluorescenceData[i];const newFluorescence=new Map;for(const[key,value]of fluorescence)newFluorescence.set(key+antennaFactor,value);fluorescenceOutputData[i]=newFluorescence}}else{realOutputData.set(realData);if(hasMaxData)maxOutputData.set(maxData);if(hasMinData)minOutputData.set(minData);if(hasAvgData)avgOutputData.set(avgData);if(hasTemplateData)templateOutputData.set(templateData);if(hasBackgroundNoiseData)backgroundNoiseOutputData.set(backgroundNoiseData);if(hasFluorescenceStats)fluorescenceOutputData=fluorescenceData}}else{const ratio=realDataLength/outputPoints;let pos=ratio/2;for(let i=0;i<outputLength;i++){const start=Math.floor(pos);const end=Math.min(Math.floor(pos+ratio),realDataLength);let realMaxVal=realData[start];let realMaxIdx=start;let maxVal=hasMaxData?maxData[start]:0;let maxIdx=start;let minVal=hasMinData?minData[start]:0;let minIdx=start;for(let j=start+1;j<end;j++){if(realData[j]>realMaxVal){realMaxVal=realData[j];realMaxIdx=j}if(hasMaxData&&maxData[j]>maxVal){maxVal=maxData[j];maxIdx=j}if(hasMinData&&minData[j]<minVal){minVal=minData[j];minIdx=j}}realOutputData[i]=applyAntennaFactor(realMaxVal,realMaxIdx);srcIndexCache[i]=realMaxIdx;if(hasMaxData)maxOutputData[i]=applyAntennaFactor(maxVal,maxIdx);if(hasMinData)minOutputData[i]=applyAntennaFactor(minVal,minIdx);if(hasAvgData){const avgValue=avgData[realMaxIdx];avgOutputData[i]=applyAntennaFactor(avgValue,realMaxIdx)}if(hasTemplateData){const templateValue=templateData[realMaxIdx];templateOutputData[i]=applyAntennaFactor(templateValue,realMaxIdx)}if(hasBackgroundNoiseData){const backgroundNoiseValue=backgroundNoiseData[realMaxIdx];backgroundNoiseOutputData[i]=applyAntennaFactor(backgroundNoiseValue,realMaxIdx)}if(hasFluorescenceStats){const fluorescence=fluorescenceData[realMaxIdx];const newFluorescence=new Map;for(const[key,value]of fluorescence)newFluorescence.set(applyAntennaFactor(key,realMaxIdx),value);fluorescenceOutputData[i]=newFluorescence}pos+=ratio}}return{realOutputData,maxOutputData,minOutputData,avgOutputData,templateOutputData,backgroundNoiseOutputData,srcIndexCache,fluorescenceOutputData}};const resampleExtraData=(extraData,antennaFactorData,antennaFactorSwitch,srcIndexCache)=>{if(!extraData||0===Object.keys(extraData).length)return{};const extraOutputData={};const extraDataKeys=Object.keys(extraData);const outputLength=srcIndexCache.length;for(let i=0;i<extraDataKeys.length;i++)extraOutputData[extraDataKeys[i]]=new Float32Array(outputLength);for(let k=0;k<extraDataKeys.length;k++){const key=extraDataKeys[k];const sourceArray=extraData[key];const outputArray=extraOutputData[key];if(antennaFactorSwitch)for(let i=0;i<outputLength;i++){const srcIndex=srcIndexCache[i];outputArray[i]=sourceArray[srcIndex]+antennaFactorData[srcIndex]}else for(let i=0;i<outputLength;i++){const srcIndex=srcIndexCache[i];outputArray[i]=sourceArray[srcIndex]}}return extraOutputData};const findExceedingDatasCore=({realData,maxData,minData,templateData,startIndex=0,endIndex,usePreallocation=false})=>{const{timestamp}=realData;const actualEndIndex=endIndex??realData.length;const segments=[];let start=-1;let sum=0;let count=0;if(usePreallocation&&0===startIndex&&actualEndIndex===realData.length){const exceedingFlags=new Uint8Array(realData.length);for(let i=0;i<realData.length;i++)exceedingFlags[i]=realData[i]>templateData[i]?1:0;for(let i=0;i<realData.length;i++)if(exceedingFlags[i]){if(-1===start){start=i;sum=realData[i];count=1}else{sum+=realData[i];count++}}else if(-1!==start){const end=i-1;if(end-start+1>=2){const avgValue=sum/count;const middleIndex=start+(end-start>>1);segments.push({maxValue:maxData[middleIndex],minValue:minData[middleIndex],avgValue,timestamp,startIndex:start,endIndex:end})}start=-1}}else for(let i=startIndex;i<Math.min(actualEndIndex,realData.length);i++){const isExceeding=realData[i]>templateData[i];if(isExceeding){if(-1===start){start=i;sum=realData[i];count=1}else{sum+=realData[i];count++}}else if(-1!==start){const end=i-1;if(end-start+1>=2){const avgValue=sum/count;const middleIndex=start+(end-start>>1);segments.push({maxValue:maxData[middleIndex],minValue:minData[middleIndex],avgValue,timestamp,startIndex:start,endIndex:end})}start=-1}}if(-1!==start){const end=actualEndIndex-1;if(end-start+1>=2){const avgValue=sum/count;const middleIndex=start+(end-start>>1);segments.push({maxValue:maxData[middleIndex],minValue:minData[middleIndex],avgValue,timestamp,startIndex:start,endIndex:end})}}return segments};const findExceedingDatas=({realData,maxData,minData,templateData})=>{if(!templateData||0===templateData.length)return[];return findExceedingDatasCore({realData,maxData,minData,templateData,usePreallocation:true})};const findExceedingDatasIncremental=({realData,maxData,minData,templateData,startIndex,endIndex,previousSegments=[]})=>{if(!templateData||0===templateData.length||startIndex>=endIndex)return previousSegments;const newSegments=findExceedingDatasCore({realData,maxData,minData,templateData,startIndex,endIndex});return[...previousSegments,...newSegments]};function isAllValid(arr){for(let i=0;i<arr.length;i++)if(!Number.isFinite(arr[i]))return false;return true}var types_ExtraDataMode=/*#__PURE__*/function(ExtraDataMode){ExtraDataMode["REPLACE"]="replace";ExtraDataMode["MERGE"]="merge";ExtraDataMode["CLEAR"]="clear";return ExtraDataMode}({});class SpectrumAnalyzer{config=DEFAULT_SPECTRUM_CONFIG;segments=[];antennaFactorData;antennaFactorSwitch;realData;maxData;minData;avgData;templateData;backgroundNoiseData;waterfallData;srcIndexCache;realOutputData;waterfallOutputData;scanProgress;lastIndex;processTimes;lastProcessTime;cachedExceedingDatas=[];fluorescenceData;fluorescenceMaxCount=0;extraData={};extraOutputData={};onSpectrumUpdate;constructor(config){const{onSpectrumUpdate,maxPoints}=config;this.onSpectrumUpdate=onSpectrumUpdate;this.config={...DEFAULT_SPECTRUM_CONFIG,...config,processing:{...DEFAULT_SPECTRUM_CONFIG.processing,...config.processing},outputRange:{start:config.outputRange?.start??0,end:config.outputRange?.end??maxPoints??SPECTRUM.OUTPUT_POINTS}};this.reset()}process({data,timestamp,segmentOffset=0,offset=0}){const processStartTime=performance.now();try{if(!data?.length)return;let index=offset;if(this.segments.length){const segment=this.segments[segmentOffset];if(!segment)throw new DataValidationError(ERROR_MESSAGES.INVALID_SEGMENT(segmentOffset));index=segment.startIndex+offset;this.scanProgress=(index+data.length)/this.config.maxPoints}else if(data.length!==this.config.maxPoints)this.updateMaxPoints(data.length);this.validateInput(data,index);const{maxPoints}=this.config;const endIndex=index+data.length;this.lastIndex=endIndex;const isOver=endIndex>=maxPoints||endIndex<this.lastIndex;this.realData.set(data,index);this.realData.timestamp=timestamp;this.processDataPoints(data,index,isOver);const processedData=this.resampleDataSeries();if(isOver)this.updateWaterfallData(this.realData,processedData.realData);const templateOverData=this.updateTemplateOverData(isOver,isOver?void 0:{startIndex:index,endIndex:index+data.length});this.notifySpectrumUpdate({...processedData,waterfallData:this.waterfallOutputData,scanProgress:this.scanProgress,processTimes:this.processTimes,...templateOverData&&{templateOverData}})}catch(error){throw error instanceof Error?error:new Error(String(error))}finally{this.lastProcessTime=performance.now()-processStartTime}}initializeSegments(segments){if(!segments?.length)throw new DataValidationError(ERROR_MESSAGES.EMPTY_SEGMENTS);let totalPoints=0;this.segments=segments.map(segment=>{const{startFrequency,stopFrequency,stepFrequency}=segment;const frequencyRange=stopFrequency-startFrequency;const stepCount=1e3*frequencyRange/stepFrequency;const pointCount=Math.round(stepCount)+1;const startIndex=totalPoints;totalPoints+=pointCount;return{startFrequency,stopFrequency,stepFrequency,pointCount,startIndex}});this.updateMaxPoints(totalPoints)}setAntennaFactor(d){const{antennaFactorData,config:{maxPoints}}=this;let data=new Float32Array(d);if(data.length!==maxPoints){data=new Float32Array(data).subarray(0,maxPoints);console.warn(ERROR_MESSAGES.INVALID_ANTENNA_FACTOR_LENGTH(maxPoints))}let hasInvalid=false;for(let i=0;i<data.length;i++){const value=data[i];const isNiceFinite=Number.isFinite(value)&&value>0;if(!isNiceFinite)hasInvalid=true;antennaFactorData[i]=isNiceFinite?value:0}if(hasInvalid)console.warn(ERROR_MESSAGES.INVALID_ANTENNA_FACTOR);if(this.antennaFactorSwitch)this.setAntennaFactorSwitch(this.antennaFactorSwitch)}setAntennaFactorSwitch(newAntennaFactorSwitch){const isChange=this.antennaFactorSwitch!==newAntennaFactorSwitch;this.antennaFactorSwitch=newAntennaFactorSwitch;if(isChange){const processedData=this.resampleDataSeries();this.resampleWaterfallOutputData();this.notifySpectrumUpdate({...processedData,waterfallData:this.waterfallOutputData})}}setWaterfallData(newWaterfallData){if(!(newWaterfallData?.[0]?.length>0))return;const{processing}=this.config;let{waterfallMaxFrames}=this.config;if(!processing.enableWaterfall)return;waterfallMaxFrames=newWaterfallData.length;this.config={...this.config,waterfallMaxFrames};this.waterfallData=newWaterfallData;this.resampleWaterfallOutputData();this.notifySpectrumUpdate({waterfallData:this.waterfallOutputData})}setRealData(data){if(!(data?.length>0)||data.length!==this.config.maxPoints)return;const newData=new Float32Array(data.length);newData.set(data);newData.timestamp=data.timestamp;this.realData=newData;const processedData=this.resampleDataSeries();this.notifySpectrumUpdate(processedData)}setMaxData(data){if(!(data?.length>0)||data.length!==this.config.maxPoints)return;const newData=new Float32Array(data.length);newData.set(data);this.maxData=newData;this.maxData.allValid=isAllValid(this.maxData);const processedData=this.resampleDataSeries();this.notifySpectrumUpdate(processedData)}setMinData(data){if(!(data?.length>0)||data.length!==this.config.maxPoints)return;const newData=new Float32Array(data.length);newData.set(data);this.minData=newData;this.minData.allValid=isAllValid(this.minData);const processedData=this.resampleDataSeries();this.notifySpectrumUpdate(processedData)}setAvgData(data){if(!(data?.length>0)||data.length!==this.config.maxPoints)return;const newData=new Float32Array(data.length);newData.set(data);this.avgData=newData;this.avgData.allValid=isAllValid(this.avgData);const processedData=this.resampleDataSeries();this.notifySpectrumUpdate(processedData)}setExtraData(data,mode=types_ExtraDataMode.MERGE){if(mode===types_ExtraDataMode.CLEAR||mode===types_ExtraDataMode.REPLACE){this.extraData={};this.extraOutputData={}}if(mode===types_ExtraDataMode.CLEAR)return;if(!data)return;for(const[key,value]of Object.entries(data)){if(!value||0===value.length){delete this.extraData[key];continue}this.extraData[key]=new Float32Array(value)}if(this.srcIndexCache?.length>0){this.extraOutputData=resampleExtraData(this.extraData,this.antennaFactorData,this.antennaFactorSwitch,this.srcIndexCache);this.notifySpectrumUpdate({extraData:this.extraOutputData})}}reset(){const{maxPoints,waterfallMaxFrames,processing:{enableMetrics,enableFluorescence}}=this.config;this.antennaFactorData=new Float32Array(maxPoints);const realData=new Float32Array(maxPoints);realData.timestamp=0;realData.fill(SPECTRUM.INITIAL_VALUE);this.realData=realData;this.maxData=new Float32Array(enableMetrics?maxPoints:0).fill(SPECTRUM.INITIAL_VALUE);this.minData=new Float32Array(enableMetrics?maxPoints:0).fill(SPECTRUM.INITIAL_VALUE);this.avgData=new Float32Array(enableMetrics?maxPoints:0).fill(SPECTRUM.INITIAL_VALUE);this.templateData=new Float32Array;this.backgroundNoiseData=new Float32Array;this.waterfallData=Array.from({length:waterfallMaxFrames},()=>{const frame=new Float32Array;frame.timestamp=0;frame.fill(SPECTRUM.INITIAL_VALUE);return frame});this.waterfallOutputData=Array.from({length:waterfallMaxFrames},()=>{const frame=new Float32Array;frame.timestamp=0;frame.fill(SPECTRUM.INITIAL_VALUE);return frame});this.fluorescenceData=enableFluorescence?Array.from({length:maxPoints},()=>new Map):[];this.fluorescenceMaxCount=0;this.extraData={};this.extraOutputData={};this.srcIndexCache=new Uint32Array(maxPoints);this.scanProgress=0;this.lastIndex=0;this.processTimes=0;this.lastProcessTime=0;this.cachedExceedingDatas=[];this.notifySpectrumUpdate({realData:this.realData,maxData:this.maxData,minData:this.minData,avgData:this.avgData,templateData:this.templateData,backgroundNoiseData:this.backgroundNoiseData,extraData:this.extraData,srcIndexCache:this.srcIndexCache,processTimes:0,scanProgress:0})}getPerformanceMetrics(){return{lastProcessTime:this.lastProcessTime,dataPoints:this.config.maxPoints,waterfallFrames:this.waterfallData.length,isInitialized:this.realData.length>0,memoryUsage:this.calculateMemoryUsage()}}updateSamplingRange(start,end){if(start<0||start>=end)throw new DataValidationError(ERROR_MESSAGES.INVALID_SAMPLING_RANGE);this.config={...this.config,outputRange:{start:Math.floor(start),end:Math.ceil(end)}};const processedData=this.resampleDataSeries();this.resampleWaterfallOutputData();this.extraOutputData=resampleExtraData(this.extraData,this.antennaFactorData,this.antennaFactorSwitch,this.srcIndexCache);this.notifySpectrumUpdate({...processedData,extraData:this.extraOutputData,waterfallData:this.waterfallOutputData});return this.srcIndexCache}setTemplateData(data){if(!data||0===data.length){this.templateData=new Float32Array(0);return}this.templateData=new Float32Array(data);if(0===this.processTimes||!this.srcIndexCache||0===this.srcIndexCache.length)return;const{srcIndexCache,config:{outputPoints}}=this;const templateOutputData=new Float32Array(outputPoints);for(let i=0;i<outputPoints;i++)templateOutputData[i]=this.templateData[srcIndexCache[i]];const templateOverData=this.updateTemplateOverData(true);this.notifySpectrumUpdate({templateData:templateOutputData,templateOverData})}setBackgroundNoiseData(data){if(!data||0===data.length){this.backgroundNoiseData=new Float32Array(0);return}this.backgroundNoiseData=new Float32Array(data);const{srcIndexCache,config:{outputPoints}}=this;const backgroundNoiseOutputData=new Float32Array(outputPoints);for(let i=0;i<outputPoints;i++)backgroundNoiseOutputData[i]=this.backgroundNoiseData[srcIndexCache[i]];this.notifySpectrumUpdate({backgroundNoiseData:backgroundNoiseOutputData})}updateTemplateOverData(forceFullCalculation=false,incrementalRange){if(!this.templateData||0===this.templateData.length){this.cachedExceedingDatas=[];return[]}let templateOverData;if(forceFullCalculation||!incrementalRange){templateOverData=findExceedingDatas({realData:this.realData,maxData:this.maxData,minData:this.minData,templateData:this.templateData});this.cachedExceedingDatas=templateOverData}else{this.cachedExceedingDatas=findExceedingDatasIncremental({realData:this.realData,maxData:this.maxData,minData:this.minData,templateData:this.templateData,startIndex:incrementalRange.startIndex,endIndex:incrementalRange.endIndex,previousSegments:this.cachedExceedingDatas});templateOverData=this.cachedExceedingDatas}return templateOverData}resampleDataSeries(){const{antennaFactorData,antennaFactorSwitch,maxData,minData,avgData,templateData,backgroundNoiseData,config:{maxPoints,outputPoints}}=this;const activeAntennaFactorData=antennaFactorSwitch?antennaFactorData:new Float32Array(maxPoints);const{realOutputData,srcIndexCache,maxOutputData,minOutputData,avgOutputData,templateOutputData,backgroundNoiseOutputData}=resampleMultiple({antennaFactorData:activeAntennaFactorData,antennaFactorSwitch,outputPoints,realData:this.getOutputData(),maxData:maxData&&maxData.length>0?this.getOutputData(maxData):void 0,minData:minData&&minData.length>0?this.getOutputData(minData):void 0,avgData:avgData&&avgData.length>0?this.getOutputData(avgData):void 0,templateData:templateData&&templateData.length>0?this.getOutputData(templateData):void 0,backgroundNoiseData:backgroundNoiseData&&backgroundNoiseData.length>0?this.getOutputData(backgroundNoiseData):void 0});this.srcIndexCache=srcIndexCache;return{realData:realOutputData,maxData:maxOutputData,minData:minOutputData,avgData:avgOutputData,templateData:templateOutputData,backgroundNoiseData:backgroundNoiseOutputData,fluorescenceData:this.getFluorescenceOutputData(),fluorescenceMaxCount:this.fluorescenceMaxCount,extraData:this.extraOutputData,srcIndexCache}}resampleWaterfallOutputData(){const{antennaFactorData,antennaFactorSwitch,waterfallData,config:{maxPoints,processing:{enableWaterfall},outputPoints}}=this;if(!enableWaterfall)return;const activeAntennaFactorData=antennaFactorSwitch?antennaFactorData:new Float32Array(maxPoints);this.waterfallOutputData=waterfallData.map(frame=>{const realData=this.getOutputData(frame);const{realOutputData}=resampleMultiple({realData,antennaFactorData:activeAntennaFactorData,antennaFactorSwitch,outputPoints});return realOutputData})}updateWaterfallData(data,outputData){const{waterfallMaxFrames,processing}=this.config;if(!processing.enableWaterfall)return;if(this.waterfallData.length>=waterfallMaxFrames){this.waterfallData.shift();this.waterfallOutputData.shift()}const newData=new Float32Array(data.length);newData.set(data);newData.timestamp=data.timestamp;this.waterfallData.push(newData);this.waterfallOutputData.push(outputData)}updateMaxPoints(maxPoints){if(this.config.maxPoints===maxPoints)return;this.config={...this.config,maxPoints,outputRange:{start:0,end:maxPoints}};this.reset()}validateInput(data,index){if(index<0||index+data.length>this.config.maxPoints)throw new IndexOutOfBoundsError(ERROR_MESSAGES.INDEX_OUT_OF_BOUNDS(index),index)}processDataPoints(data,index,isOver){const{maxData,minData,avgData,config:{processing:{enableMetrics}}}=this;if(!enableMetrics)return;if(isOver){this.processTimes+=1;if(!maxData.allValid)maxData.allValid=isAllValid(maxData);if(!minData.allValid)minData.allValid=isAllValid(minData);if(!avgData.allValid)avgData.allValid=isAllValid(avgData)}let allValid=true;const length=data.length;for(let i=0;i<length;i++)if(!Number.isFinite(data[i])){allValid=false;break}for(let i=0;i<length;i++){const dataIndex=index+i;const value=data[i];if(!allValid&&!Number.isFinite(value))continue;const oldMax=maxData[dataIndex];if(value>oldMax||!maxData.allValid&&Number.isNaN(oldMax))maxData[dataIndex]=value;const oldMin=minData[dataIndex];if(value<oldMin||!minData.allValid&&Number.isNaN(oldMin))minData[dataIndex]=value;const oldAvg=avgData[dataIndex];if(0===this.processTimes||Number.isNaN(oldAvg))avgData[dataIndex]=value;else avgData[dataIndex]=oldAvg+(value-oldAvg)/(this.processTimes+1);this.updateFluorescenceStats(dataIndex,value)}}updateFluorescenceStats(dataIndex,value){const{processing}=this.config;if(!processing.enableFluorescence||!this.fluorescenceData)return;if(!Number.isFinite(value))return;const level=Math.round(value);let levelMap=this.fluorescenceData[dataIndex];if(!levelMap){levelMap=new Map;this.fluorescenceData[dataIndex]=levelMap}const currentCount=levelMap.get(level)??0;const newCount=currentCount+1;levelMap.set(level,newCount);if(newCount>this.fluorescenceMaxCount)this.fluorescenceMaxCount=newCount}notifySpectrumUpdate(processedData){this.onSpectrumUpdate?.(processedData)}calculateMemoryUsage(){const arraySize=this.config.maxPoints*Float32Array.BYTES_PER_ELEMENT;const baseArrayMemory=4*arraySize;const rawWaterfallMemory=this.waterfallData.reduce((sum,frame)=>sum+frame.length*Float32Array.BYTES_PER_ELEMENT,0);const outputWaterfallMemory=this.waterfallOutputData.reduce((sum,frame)=>sum+frame.length*Float32Array.BYTES_PER_ELEMENT,0);return baseArrayMemory+rawWaterfallMemory+outputWaterfallMemory}getOutputData(data){const{outputRange:{start,end}}=this.config;const sourceData=data??this.realData;const outputData=sourceData.subarray(start,end);outputData.timestamp=sourceData.timestamp;return outputData}getFluorescenceOutputData(data){const{outputRange:{start,end}}=this.config;const sourceData=data??this.fluorescenceData;if(!sourceData||0===sourceData.length)return;return sourceData.slice(start,end)}getAllRawData(){const{realData,maxData,minData,avgData,templateData,backgroundNoiseData,fluorescenceData,waterfallData,extraData,srcIndexCache}=this;return{realData,maxData,minData,avgData,templateData,backgroundNoiseData,fluorescenceData,waterfallData,extraData,srcIndexCache}}}var types_OrientationType=/*#__PURE__*/function(OrientationType){OrientationType["Horizontal"]="horizontal";OrientationType["Vertical"]="vertical";return OrientationType}({});var types_GraphicType=/*#__PURE__*/function(GraphicType){GraphicType["Circle"]="circle";GraphicType["Rect"]="rect";GraphicType["Line"]="line";GraphicType["Stepline"]="stepline";GraphicType["Bar"]="bar";GraphicType["Area"]="area";return GraphicType}({});var types_SeriesEventType=/*#__PURE__*/function(SeriesEventType){SeriesEventType["PropertyChanged"]="propertyChanged";SeriesEventType["SeriesAdded"]="seriesAdded";SeriesEventType["SeriesRemoved"]="seriesRemoved";SeriesEventType["SeriesCleared"]="seriesCleared";return SeriesEventType}({});const DEFAULT_SERIES_CONFIG={thickness:1,orientation:types_OrientationType.Horizontal,display:true,type:types_GraphicType.Line,color:"#00000000",label:""};class SeriesManager{seriesMap=new Map;changeCallbacks=[];subscribers=new Map;constructor(initialSeries=[]){this.initializeSeries(initialSeries)}initializeSeries(seriesConfigs){for(const config of seriesConfigs)this.addSeries(config)}addSeries(config){const fullConfig={...DEFAULT_SERIES_CONFIG,...config};this.seriesMap.set(config.name,fullConfig);this.emitEvent({type:types_SeriesEventType.SeriesAdded,name:config.name,series:fullConfig})}getSeries(name){return this.seriesMap.get(name)}getAllSeries(){return Array.from(this.seriesMap.values())}getAllConfigs(){const configs={};for(const[name,config]of this.seriesMap)configs[name]={...config};return configs}setSeriesProperty(name,property,value){const series=this.seriesMap.get(name);if(!series)return false;if("name"===property)return false;const oldValue=series[property];const updatedSeries={...series,[property]:value};this.seriesMap.set(name,updatedSeries);this.notifyChange(name,property,value);this.emitEvent({type:types_SeriesEventType.PropertyChanged,name,property,value,oldValue,series:updatedSeries});return true}removeSeries(name){const series=this.seriesMap.get(name);if(!series)return false;const deleted=this.seriesMap.delete(name);if(deleted)this.emitEvent({type:types_SeriesEventType.SeriesRemoved,name,series});return deleted}hasSeries(name){return this.seriesMap.has(name)}onChange(callback){this.changeCallbacks.push(callback)}offChange(callback){const index=this.changeCallbacks.indexOf(callback);if(index>-1)this.changeCallbacks.splice(index,1)}notifyChange(name,property,value){for(const callback of this.changeCallbacks)callback(name,property,value)}clear(){this.seriesMap.clear();this.emitEvent({type:types_SeriesEventType.SeriesCleared})}size(){return this.seriesMap.size}subscribe(subscriber,options={}){this.subscribers.set(subscriber,options);if(options.immediate){for(const series of this.seriesMap.values())if(this.shouldNotifySubscriber(subscriber,{type:types_SeriesEventType.SeriesAdded,name:series.name,series}))subscriber({type:types_SeriesEventType.SeriesAdded,name:series.name,series})}return()=>{this.subscribers.delete(subscriber)}}unsubscribe(subscriber){this.subscribers.delete(subscriber)}emitEvent(event){for(const[subscriber]of this.subscribers)if(this.shouldNotifySubscriber(subscriber,event))subscriber(event)}shouldNotifySubscriber(subscriber,event){const options=this.subscribers.get(subscriber);if(!options)return false;if(options.eventTypes&&!options.eventTypes.includes(event.type))return false;if(options.seriesNames&&event.name&&!options.seriesNames.includes(event.name))return false;return true}}export{DataValidationError,ERROR_MESSAGES,types_GraphicType as GraphicType,IndexOutOfBoundsError,LevelStreamAnalyzer,types_OrientationType as OrientationType,SPECTRUM,types_SeriesEventType as SeriesEventType,SeriesManager,SpectrumAnalyzer,SpectrumError};
|