Skip to content

Commit 98e1b6b

Browse files
Updates to get onboard processing to match how Alan's firmware works
1 parent 2ded5f6 commit 98e1b6b

File tree

4 files changed

+25
-27
lines changed

4 files changed

+25
-27
lines changed

suncet_instrument_simulator/config_files/config_default.ini

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -84,17 +84,17 @@ exposure_time_long = 15
8484
# [seconds] This isn't actually part of SHDR but is necessary because the model has its own timestep that we aren't fully accounting for
8585
model_timestep = 10
8686
# the stack is then used to remove particle hits by, e.g., taking the median
87-
num_short_exposures_to_stack = 10
87+
num_short_exposures_to_stack = 9
8888
# the stack is then used to remove particle hits by, e.g., taking the median]
89-
num_long_exposures_to_stack = 3
89+
num_long_exposures_to_stack = 4
9090
# this value is centered around the middle row; e.g., a value of 101 would be ±50 rows around the central row
9191
num_inner_rows_for_short_exposure = 540
9292
# [solar radii] what circle to use of short exposures for the composite image
9393
inner_fov_circle_radius = 1.33
9494
# [arcsec/s] 0.6372 is 1sigma rms jitter from MinXSS-1 and CSIM
9595
jitter = 0.6372
96-
# [integer] how many bit shift places to get particle filtering (which uses a 24-bit sum) to fit back down into 16-bit; each bit shift place is a divide by 2
97-
num_shift_bits_24_to_16 = 2
96+
# [integer] how many bit shift places to get the onboard temporary processing buffer (32-bit) to fit back down into storage buffer (16-bit); each bit shift place is a divide by 2
97+
num_shift_bits_32_to_16 = 2
9898

9999
[histogram]
100100
# [number] the number of bins in the histogram

suncet_instrument_simulator/config_parser.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ def __init__(self, filename):
6969
self.num_inner_rows_for_short_exposure = config['shdr'].getint('num_inner_rows_for_short_exposure')
7070
self.inner_fov_circle_radius = config['shdr'].getfloat('inner_fov_circle_radius') * u.solRad
7171
self.jitter = config['shdr'].getfloat('jitter') * u.arcsec / u.second
72-
self.num_shift_bits_24_to_16 = config['shdr'].getint('num_shift_bits_24_to_16')
72+
self.num_shift_bits_32_to_16 = config['shdr'].getint('num_shift_bits_32_to_16')
7373

7474
# histogram
7575
self.num_bins = config['histogram'].getint('num_bins')

suncet_instrument_simulator/instrument.py

Lines changed: 19 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -572,24 +572,18 @@ def filter_out_particle_hits(self, onboard_processed_images):
572572
for exposure_type in ['short exposure', 'long exposure']:
573573
map_indices = list(onboard_processed_images[exposure_type].keys())
574574

575-
if len(map_indices) != 3:
576-
raise ValueError("Need exactly 3 images to apply particle filtering per Alan's CSIE FPGA logic.")
577-
578-
sorted_indices = sorted(map_indices)[:3]
575+
sorted_indices = sorted(map_indices)
579576
maps = [onboard_processed_images[exposure_type][index] for index in sorted_indices]
580577
stack = np.stack([map_obj.data for map_obj in maps], axis=-1)
581578

582-
stack = stack.astype(np.int32) # Note: onboard firmware actually uses a 24-bit buffer for the following sum but numpy only has options of 16 or 32. This is fine in most cases for simulation because even 24 bit is really, really big.
583-
584-
# Remove max value along the stack axis and sum the remaining values
585-
max_removed = np.sort(stack, axis=-1)[:, :, :-1] # Sort and remove last (max) value
586-
summed_data = np.sum(max_removed, axis=-1) # Sum the remaining values
579+
stack = stack.astype(np.int32)
587580

588-
# Shift the data to the right by the number of bits specified in the config to get big numbers to still fit in 16 bits
589-
shift_factor = 2 ** self.config.num_shift_bits_24_to_16
590-
shifted_data = (summed_data / shift_factor).astype(np.uint16)
581+
# Sum all values first, then subtract the maximum value (that's how flight firmware does it)
582+
summed_data = np.sum(stack, axis=-1)
583+
max_values = np.max(stack, axis=-1)
584+
summed_data = summed_data - max_values
591585

592-
new_map = sunpy.map.Map(shifted_data, maps[0].meta)
586+
new_map = sunpy.map.Map(summed_data, maps[0].meta)
593587
onboard_processed_images[exposure_type] = new_map
594588

595589
return onboard_processed_images
@@ -643,10 +637,6 @@ def bin_image(self, onboard_processed_images, xbin=None, ybin=None):
643637
---
644638
detector_images : [sunpy.map.MapSequence]
645639
A binned sunpy detector images map sequence
646-
647-
TODO
648-
---
649-
check if input is a sunpy map
650640
'''
651641
# check if bin dimensions added
652642
if xbin == None:
@@ -671,16 +661,23 @@ def bin_image(self, onboard_processed_images, xbin=None, ybin=None):
671661
onboard_processed_images = onboard_processed_images.resample(new_dimensions, method='nearest')
672662
onboard_processed_images *= (xbin * ybin) # Conserve energy. DN come from electrons. resample doesn't account for the fact that the total number of electrons (DN) recorded across the detector is the same regardless of how you bin them in software
673663

674-
# Flight firmware uses 24 bits when doing summing to avoid rollover that would otherwise be possible at 16 bits
675-
max_24bit = 2**24 - 1
676-
data_24_bit = np.clip(onboard_processed_images.data, 0, max_24bit).astype(np.uint32)
677-
678-
new_map = sunpy.map.Map(data_24_bit, onboard_processed_images.meta)
664+
new_map = sunpy.map.Map(onboard_processed_images.data, onboard_processed_images.meta)
679665
new_map.meta['cdelt1'] = self.config.plate_scale.value * xbin # Note 1: this is only needed because sunpy (v4.0.1) resample updates dimensions but NOT plate scale
680666
new_map.meta['cdelt2'] = self.config.plate_scale.value * ybin # Note 2: there is also risk here because a) the user must be responsible in the config file to ensure the image_dimensions and plate_scale are compatible, and b) the units they input for plate_scale must be the same as those already in the map
681667

682668
return new_map
683669

670+
def bit_shift_data(self, onboard_processed_images):
671+
672+
# Shift the data to the right by the number of bits specified in the config to get big numbers to still fit in 16 bits
673+
shift_factor = 2 ** self.config.num_shift_bits_32_to_16
674+
shifted_data = (onboard_processed_images.data / shift_factor).astype(np.uint32)
675+
676+
max_value = 2**self.config.readout_bits.value - 1
677+
data = np.clip(shifted_data, 0, max_value).astype(np.uint16)
678+
new_map = sunpy.map.Map(data, onboard_processed_images.meta)
679+
680+
return new_map
684681

685682
def compress_image(self, onboard_processed_images):
686683
normalized_data = (onboard_processed_images.data - np.min(onboard_processed_images.data)) / (np.max(onboard_processed_images.data) - np.min(onboard_processed_images.data))

suncet_instrument_simulator/simulator.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ def __apply_camera_software(self):
136136
self.onboard_processed_images = self.onboard_software.create_composite(self.onboard_processed_images)
137137
self.image_histogram = self.onboard_software.create_image_histogram(self.onboard_processed_images)
138138
self.onboard_processed_images = self.onboard_software.bin_image(self.onboard_processed_images)
139+
self.onboard_processed_images = self.onboard_software.bit_shift_data(self.onboard_processed_images)
139140
if self.config.compress_image:
140141
self.onboard_processed_images = self.onboard_software.compress_image(self.onboard_processed_images)
141142

0 commit comments

Comments
 (0)