Wideband autonomous SDR analysis engine forked from sdr-visual-suite
25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.

178 satır
4.5KB

  1. package main
  2. import (
  3. "sort"
  4. "sdr-wideband-suite/internal/pipeline"
  5. )
  6. type SurveillanceLevelSummary struct {
  7. Name string `json:"name"`
  8. Role string `json:"role,omitempty"`
  9. Truth string `json:"truth,omitempty"`
  10. SampleRate int `json:"sample_rate,omitempty"`
  11. FFTSize int `json:"fft_size,omitempty"`
  12. BinHz float64 `json:"bin_hz,omitempty"`
  13. Decimation int `json:"decimation,omitempty"`
  14. SpanHz float64 `json:"span_hz,omitempty"`
  15. CenterHz float64 `json:"center_hz,omitempty"`
  16. Source string `json:"source,omitempty"`
  17. SpectrumBins int `json:"spectrum_bins,omitempty"`
  18. }
  19. type CandidateEvidenceSummary struct {
  20. Level string `json:"level"`
  21. Provenance string `json:"provenance,omitempty"`
  22. Count int `json:"count"`
  23. }
  24. type CandidateEvidenceStateSummary struct {
  25. Total int `json:"total"`
  26. WithEvidence int `json:"with_evidence"`
  27. Fused int `json:"fused"`
  28. MultiLevelConfirmed int `json:"multi_level_confirmed"`
  29. DerivedOnly int `json:"derived_only"`
  30. PrimaryOnly int `json:"primary_only"`
  31. }
  32. func buildSurveillanceLevelSummaries(set pipeline.SurveillanceLevelSet, spectra []pipeline.SurveillanceLevelSpectrum) map[string]SurveillanceLevelSummary {
  33. if set.Primary.Name == "" && len(set.Derived) == 0 && len(set.Support) == 0 && set.Presentation.Name == "" && len(set.All) == 0 {
  34. return nil
  35. }
  36. bins := map[string]int{}
  37. for _, spec := range spectra {
  38. if spec.Level.Name == "" || len(spec.Spectrum) == 0 {
  39. continue
  40. }
  41. bins[spec.Level.Name] = len(spec.Spectrum)
  42. }
  43. levels := set.All
  44. if len(levels) == 0 {
  45. if set.Primary.Name != "" {
  46. levels = append(levels, set.Primary)
  47. }
  48. if len(set.Derived) > 0 {
  49. levels = append(levels, set.Derived...)
  50. }
  51. if len(set.Support) > 0 {
  52. levels = append(levels, set.Support...)
  53. }
  54. if set.Presentation.Name != "" {
  55. levels = append(levels, set.Presentation)
  56. }
  57. }
  58. out := make(map[string]SurveillanceLevelSummary, len(levels))
  59. for _, level := range levels {
  60. name := level.Name
  61. if name == "" {
  62. continue
  63. }
  64. binHz := level.BinHz
  65. if binHz == 0 && level.SampleRate > 0 && level.FFTSize > 0 {
  66. binHz = float64(level.SampleRate) / float64(level.FFTSize)
  67. }
  68. out[name] = SurveillanceLevelSummary{
  69. Name: name,
  70. Role: level.Role,
  71. Truth: level.Truth,
  72. SampleRate: level.SampleRate,
  73. FFTSize: level.FFTSize,
  74. BinHz: binHz,
  75. Decimation: level.Decimation,
  76. SpanHz: level.SpanHz,
  77. CenterHz: level.CenterHz,
  78. Source: level.Source,
  79. SpectrumBins: bins[name],
  80. }
  81. }
  82. if len(out) == 0 {
  83. return nil
  84. }
  85. return out
  86. }
  87. func buildCandidateSourceSummary(candidates []pipeline.Candidate) map[string]int {
  88. if len(candidates) == 0 {
  89. return nil
  90. }
  91. out := map[string]int{}
  92. for _, cand := range candidates {
  93. if cand.Source == "" {
  94. continue
  95. }
  96. out[cand.Source]++
  97. }
  98. if len(out) == 0 {
  99. return nil
  100. }
  101. return out
  102. }
  103. func buildCandidateEvidenceSummary(candidates []pipeline.Candidate) []CandidateEvidenceSummary {
  104. if len(candidates) == 0 {
  105. return nil
  106. }
  107. type key struct {
  108. level string
  109. provenance string
  110. }
  111. counts := map[key]int{}
  112. for _, cand := range candidates {
  113. for _, ev := range cand.Evidence {
  114. name := ev.Level.Name
  115. if name == "" {
  116. name = "unknown"
  117. }
  118. k := key{level: name, provenance: ev.Provenance}
  119. counts[k]++
  120. }
  121. }
  122. if len(counts) == 0 {
  123. return nil
  124. }
  125. out := make([]CandidateEvidenceSummary, 0, len(counts))
  126. for k, v := range counts {
  127. out = append(out, CandidateEvidenceSummary{Level: k.level, Provenance: k.provenance, Count: v})
  128. }
  129. sort.Slice(out, func(i, j int) bool {
  130. if out[i].Count == out[j].Count {
  131. if out[i].Level == out[j].Level {
  132. return out[i].Provenance < out[j].Provenance
  133. }
  134. return out[i].Level < out[j].Level
  135. }
  136. return out[i].Count > out[j].Count
  137. })
  138. return out
  139. }
  140. func buildCandidateEvidenceStateSummary(candidates []pipeline.Candidate) *CandidateEvidenceStateSummary {
  141. if len(candidates) == 0 {
  142. return nil
  143. }
  144. summary := CandidateEvidenceStateSummary{Total: len(candidates)}
  145. for _, cand := range candidates {
  146. state := pipeline.CandidateEvidenceStateFor(cand)
  147. if state.TotalLevelEntries == 0 {
  148. continue
  149. }
  150. summary.WithEvidence++
  151. if state.Fused {
  152. summary.Fused++
  153. }
  154. if state.MultiLevelConfirmed {
  155. summary.MultiLevelConfirmed++
  156. }
  157. if state.DerivedOnly {
  158. summary.DerivedOnly++
  159. }
  160. if state.PrimaryLevelCount > 0 && state.DerivedLevelCount == 0 {
  161. summary.PrimaryOnly++
  162. }
  163. }
  164. if summary.WithEvidence == 0 {
  165. return nil
  166. }
  167. return &summary
  168. }