@@ -62,7 +62,8 @@ import androidx.core.net.toUri
6262import com.github.mikephil.charting.components.Legend
6363import io.github.vikulin.opengammakit.math.SpectrumModifier
6464import io.github.vikulin.opengammakit.math.SpectrumModifier.smartPeakDetect
65- import io.github.vikulin.opengammakit.model.EnergySpectrum
65+ import io.github.vikulin.opengammakit.model.DerivedSpectrumEntry
66+ import io.github.vikulin.opengammakit.model.ModifierInfo
6667import io.github.vikulin.opengammakit.model.GammaKitEntry
6768import io.github.vikulin.opengammakit.view.FwhmSpectrumSelectionDialogFragment
6869import io.github.vikulin.opengammakit.view.SaveSelectedSpectrumDialogFragment
@@ -355,9 +356,9 @@ class SpectrumFragment : SerialConnectionFragment(),
355356 xAxis.limitLines.removeIf { it.label.startsWith(" P@" ) }
356357
357358 // Assume you are working with spectrum index = 0
358- val energySpectrum = spectrumDataSet.data [0 ].resultData.energySpectrum
359- val peaks = energySpectrum.peaks
360- if (peaks.isEmpty ()) return
359+ val energySpectrum = spectrumDataSet.derivedSpectra [0 ]
360+ val peaks = energySpectrum? .peaks
361+ if (peaks.isNullOrEmpty ()) return
361362
362363 val sortedCalibrationList = verticalCalibrationLineList.sortedBy { it.second.first }
363364
@@ -540,24 +541,22 @@ class SpectrumFragment : SerialConnectionFragment(),
540541 private fun setupChart () {
541542 val primaryColor = resources.getColor(R .color.colorPrimaryText, null )
542543 // copy data to outputSpectrum
543- spectrumDataSet.data.mapIndexed { index, entry ->
544- if (entry.resultData.energySpectrum.filters.isEmpty()){
545- resetSpectrumData(entry.resultData.energySpectrum)
546- }
544+ if (spectrumDataSet.derivedSpectra.isEmpty()){
545+ resetSpectrumData(spectrumDataSet)
547546 }
548547 // Create LineDataSets from each GammaKitEntry in spectrumDataSet
549- val dataSets = spectrumDataSet.data.mapIndexed { index, entry ->
550- val spectrum = entry.resultData.energySpectrum.outputSpectrum
548+ val dataSets = spectrumDataSet.derivedSpectra.map { entry ->
549+ val spectrum = entry.value.resultSpectrum
551550 val entries = spectrum.mapIndexed { ch, count ->
552551 Entry (ch.toFloat(), count.toFloat())
553552 }
554- val label = getSpectrumLabel(index, entry)
553+ val label = getSpectrumLabel(entry.key, spectrumDataSet.data[ entry.key] )
555554 LineDataSet (entries, label).apply {
556555 mode = LineDataSet .Mode .CUBIC_BEZIER
557556 lineWidth = 1.5f
558557 setDrawCircles(false )
559558 setDrawValues(false )
560- color = getLineColor(requireContext(), index )
559+ color = getLineColor(requireContext(), entry.key )
561560 }
562561 }
563562
@@ -609,18 +608,18 @@ class SpectrumFragment : SerialConnectionFragment(),
609608
610609 private fun updateChartSpectrumData () {
611610
612- val dataSets = spectrumDataSet.data.mapIndexed { index, entry ->
613- val spectrum = entry.resultData.energySpectrum.outputSpectrum
611+ val dataSets = spectrumDataSet.derivedSpectra.map { entry ->
612+ val spectrum = entry.value.resultSpectrum
614613 val entries = spectrum.mapIndexed { ch, count ->
615614 Entry (ch.toFloat(), count.toFloat())
616615 }
617- val label = getSpectrumLabel(index, entry)
616+ val label = getSpectrumLabel(entry.key, spectrumDataSet.data[ entry.key] )
618617 LineDataSet (entries, label).apply {
619618 mode = LineDataSet .Mode .CUBIC_BEZIER
620619 lineWidth = 1.5f
621620 setDrawCircles(false )
622621 setDrawValues(false )
623- color = getLineColor(requireContext(), index )
622+ color = getLineColor(requireContext(), entry.key )
624623 }
625624 }
626625
@@ -820,8 +819,8 @@ class SpectrumFragment : SerialConnectionFragment(),
820819 energySpectrum.numberOfChannels = spectrum.size
821820 energySpectrum.measurementTime =
822821 (SystemClock .elapsedRealtime() - measureTimer.base)/ 1000
823- // copy spectrum. TODO apply filters and peaks detection
824- resetSpectrumData(energySpectrum )
822+ // copy spectrum. TODO apply modifiers and peaks detection
823+ resetSpectrumData(spectrumDataSet )
825824
826825 updateChartSpectrumData()
827826 } catch (e: Exception ) {
@@ -860,10 +859,8 @@ class SpectrumFragment : SerialConnectionFragment(),
860859 " Parsed scheduled spectrum number: ${openGammaKitData.data.size} "
861860 )
862861 spectrumDataSet.data[deviceSpectrumIndex] = openGammaKitData.data[deviceSpectrumIndex]
863- var energySpectrum = spectrumDataSet.data[deviceSpectrumIndex].
864- resultData.energySpectrum
865- // copy spectrum. TODO apply filters and peaks detection
866- resetSpectrumData(energySpectrum)
862+ // copy spectrum. TODO apply modifiers and peaks detection
863+ resetSpectrumData(spectrumDataSet)
867864 updateChartSpectrumData()
868865 } catch (e: Exception ) {
869866 Log .e(" Test" , " Failed to parse data: ${e.message} " )
@@ -1517,96 +1514,149 @@ class SpectrumFragment : SerialConnectionFragment(),
15171514 index in selectedIndexes
15181515 }.toMutableList()
15191516
1520- // Create a new OpenGammaKitData with the same schema version and filtered data
1521- val filteredData = OpenGammaKitData (
1517+ // Create a new OpenGammaKitData with the same schema version and modified data
1518+ val modifiedData = OpenGammaKitData (
15221519 schemaVersion = spectrumDataSet.schemaVersion,
15231520 data = selectedEntries
15241521 )
15251522
1526- // Call save method with the filtered data
1527- saveGammaKitDataAsJson(requireContext(), filteredData )
1523+ // Call save method with the modified data
1524+ saveGammaKitDataAsJson(requireContext(), modifiedData )
15281525 }
15291526
1530- private fun toggleSavitzkyGolayFilter (){
1531- for (entry in spectrumDataSet.data) {
1532- val energy = entry.resultData.energySpectrum
1533- if (! energy.filters.contains(" SavitzkyGolay" )) {
1534- // Apply filter and add tag
1535- val inputSpectrum = if (energy.filters.isNotEmpty()) {
1536- entry.resultData.energySpectrum.outputSpectrum
1537- } else {
1538- entry.resultData.energySpectrum.spectrum.map { it.toDouble() }
1539- }
1540- SpectrumModifier .applySavitzkyGolayFilter(inputSpectrum, entry)
1541- entry.resultData.energySpectrum.filters.add(" SavitzkyGolay" )
1542- } else {
1543- energy.filters.clear()
1544- resetSpectrumData(energy)
1527+ private fun toggleSavitzkyGolayFilter () {
1528+ val alreadyModified = alreadyModified(" SavitzkyGolay" )
1529+
1530+ if (! alreadyModified) {
1531+ // Apply Savitzky-Golay modifier for each original spectrum
1532+ spectrumDataSet.data.forEachIndexed { index, entry ->
1533+ val inputSpectrum = entry.resultData.energySpectrum.spectrum.map { it.toDouble() }
1534+
1535+ val modified = SpectrumModifier .applySavitzkyGolayFilter(inputSpectrum)
1536+
1537+ val derivedEntry = DerivedSpectrumEntry (
1538+ name = " ${entry.deviceData.deviceName} - SavitzkyGolay" ,
1539+ resultSpectrum = modified,
1540+ modifiers = mutableListOf (
1541+ ModifierInfo (
1542+ modifierName = " SavitzkyGolay" ,
1543+ inputIndexes = listOf (index)
1544+ )
1545+ )
1546+ )
1547+
1548+ spectrumDataSet.derivedSpectra[index] = derivedEntry
15451549 }
1550+ } else {
1551+ // Reset: clear all derived spectra and add raw versions only
1552+ resetSpectrumData(spectrumDataSet)
15461553 }
15471554 }
15481555
1549- private fun applySavitzkyGolayFilter (apply : Boolean ) {
1550- for (entry in spectrumDataSet.data) {
1551- val energy = entry.resultData.energySpectrum
1552- if (apply) {
1553- if (! energy.filters.contains(" SavitzkyGolay" )) {
1554- // Apply filter and add tag
1555- val inputSpectrum = if (energy.filters.isNotEmpty()) {
1556- entry.resultData.energySpectrum.outputSpectrum
1557- } else {
1558- entry.resultData.energySpectrum.spectrum.map { it.toDouble() }
1559- }
1560- SpectrumModifier .applySavitzkyGolayFilter(inputSpectrum, entry)
1561- entry.resultData.energySpectrum.filters.add(" SavitzkyGolay" )
1562- }
1563- } else {
1564- energy.filters.clear()
1565- resetSpectrumData(energy)
1566- }
1556+ private fun alreadyModified (modifierName : String ): Boolean {
1557+ val alreadyModified = spectrumDataSet.derivedSpectra.any { derived ->
1558+ derived.value.modifiers.any { it.modifierName == modifierName}
15671559 }
1560+ return alreadyModified
15681561 }
15691562
1570- private fun resetSpectrumData ( energySpectrum : EnergySpectrum ) {
1571- energySpectrum.outputSpectrum =
1572- energySpectrum.spectrum.map { count ->
1573- count.toDouble()
1574- }.toMutableList()
1563+ private fun alreadyModified ( modifierName : String , index : Int ): Boolean {
1564+ val alreadyModified = spectrumDataSet.derivedSpectra.any { derived ->
1565+ derived.value.modifiers.any { it.modifierName == modifierName && it.inputIndexes == listOf (index)}
1566+ }
1567+ return alreadyModified
15751568 }
15761569
1577- private fun toggleLogScaleFilter (){
1578- for (entry in spectrumDataSet.data) {
1579- val energy = entry.resultData.energySpectrum
1580- if (! energy.filters.contains(" LogScale" )) {
1581- // Apply filter and add tag
1582- applyLogScale(entry, true )
1583- } else {
1584- applyLogScale(entry, false )
1570+ private fun applySavitzkyGolayFilter (apply : Boolean ) {
1571+ if (apply) {
1572+ spectrumDataSet.data.forEachIndexed { index, entry ->
1573+ // Skip if a SavitzkyGolay-derived spectrum already exists for this input
1574+ val alreadyModified = alreadyModified(" SavitzkyGolay" , index)
1575+
1576+ if (alreadyModified) return @forEachIndexed
1577+
1578+ val inputSpectrum = entry.resultData.energySpectrum.spectrum.map { it.toDouble() }
1579+
1580+ val modified = SpectrumModifier .applySavitzkyGolayFilter(inputSpectrum)
1581+
1582+ val derivedEntry = DerivedSpectrumEntry (
1583+ name = " ${entry.deviceData.deviceName} - SavitzkyGolay" ,
1584+ resultSpectrum = modified,
1585+ modifiers = mutableListOf (
1586+ ModifierInfo (
1587+ modifierName = " SavitzkyGolay" ,
1588+ inputIndexes = listOf (index)
1589+ )
1590+ )
1591+ )
1592+
1593+ spectrumDataSet.derivedSpectra[index] = derivedEntry
15851594 }
1595+ } else {
1596+ // Remove all derived spectra and replace with raw versions
1597+ resetSpectrumData(spectrumDataSet)
1598+ }
1599+ }
1600+
1601+ private fun resetSpectrumData (dataSet : OpenGammaKitData ){
1602+ // Remove all derived spectra and replace with raw versions
1603+ dataSet.derivedSpectra.clear()
1604+ dataSet.data.forEachIndexed { index, entry ->
1605+ val raw = entry.resultData.energySpectrum.spectrum.map { it.toDouble() }
1606+
1607+ val baseEntry = DerivedSpectrumEntry (
1608+ name = " Raw" ,
1609+ resultSpectrum = raw,
1610+ modifiers = mutableListOf () // Now empty
1611+ )
1612+
1613+ spectrumDataSet.derivedSpectra[index] = baseEntry
15861614 }
15871615 }
15881616
1589- fun applyLogScale (entry : GammaKitEntry , apply : Boolean ) {
1590- entry.resultData.energySpectrum.applyLogScale(apply)
1617+ private fun toggleLogScaleFilter () {
1618+ val alreadyModified = alreadyModified(" LogScale" )
1619+
1620+ if (! alreadyModified) {
1621+ spectrumDataSet.data.forEachIndexed { index, entry ->
1622+ applyLogScale(spectrumDataSet, entry, index, apply = true )
1623+ }
1624+ } else {
1625+ // Reset: clear all derived spectra and add raw versions only
1626+ resetSpectrumData(spectrumDataSet)
1627+ }
15911628 }
15921629
1593- fun EnergySpectrum.applyLogScale (apply : Boolean ) {
1630+ fun applyLogScale (
1631+ dataSet : OpenGammaKitData ,
1632+ entry : GammaKitEntry ,
1633+ index : Int ,
1634+ apply : Boolean
1635+ ) {
15941636 if (apply) {
1595- if (! filters.contains(" LogScale" )) {
1596- val inputSpectrum = if (filters.isNotEmpty()) {
1597- outputSpectrum
1598- } else {
1599- spectrum.map { it.toDouble() }
1600- }
1601- outputSpectrum = inputSpectrum.map { count ->
1602- val adjusted = if (count > 1L ) count.toDouble() else 1.0
1637+
1638+ val alreadyModified = alreadyModified(" LogScale" , index)
1639+
1640+ if (! alreadyModified) {
1641+ val inputSpectrum = entry.resultData.energySpectrum.spectrum.map { it.toDouble() }
1642+ val logScaled = inputSpectrum.map { count ->
1643+ val adjusted = if (count > 1.0 ) count else 1.0
16031644 log10(adjusted)
1604- }.toMutableList()
1605- filters.add(" LogScale" )
1645+ }
1646+
1647+ val derivedEntry = DerivedSpectrumEntry (
1648+ name = " ${entry.deviceData.deviceName} - LogScale" ,
1649+ resultSpectrum = logScaled,
1650+ modifiers = mutableListOf (
1651+ ModifierInfo (
1652+ modifierName = " LogScale" ,
1653+ inputIndexes = listOf (index)
1654+ )
1655+ )
1656+ )
1657+
1658+ spectrumDataSet.derivedSpectra[index] = derivedEntry
16061659 }
1607- } else {
1608- filters.clear()
1609- resetSpectrumData(this )
16101660 }
16111661 }
16121662
0 commit comments