{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":101849,"databundleVersionId":13093295,"sourceType":"competition"}],"dockerImageVersionId":31089,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import os\nimport itertools\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\n\nfrom astropy.stats import sigma_clip\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-07T04:02:50.546937Z","iopub.execute_input":"2025-09-07T04:02:50.54727Z","iopub.status.idle":"2025-09-07T04:02:50.552823Z","shell.execute_reply.started":"2025-09-07T04:02:50.547241Z","shell.execute_reply":"2025-09-07T04:02:50.551622Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Defining the paths","metadata":{}},{"cell_type":"code","source":"input_path = r'/kaggle/input/ariel-data-challenge-2025/'\noutput_path = r'/kaggle/working/tmp/data_processed/'","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-07T03:57:34.422433Z","iopub.execute_input":"2025-09-07T03:57:34.422936Z","iopub.status.idle":"2025-09-07T03:57:34.427764Z","shell.execute_reply.started":"2025-09-07T03:57:34.422901Z","shell.execute_reply":"2025-09-07T03:57:34.426741Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"if not os.path.exists(output_path):\n    os.makedirs(output_path)\n    print(f'Directory made : {output_path}')\nelse:\n    print(f'Directory exists : {output_path}')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-07T03:57:34.509408Z","iopub.execute_input":"2025-09-07T03:57:34.509716Z","iopub.status.idle":"2025-09-07T03:57:34.516441Z","shell.execute_reply.started":"2025-09-07T03:57:34.509693Z","shell.execute_reply":"2025-09-07T03:57:34.515436Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Read the data","metadata":{}},{"cell_type":"code","source":"# Understanding the dataset.\n\n# 1. adc Info.\nadc_info = pd.read_csv(input_path + 'adc_info.csv')\n# 2. axis Info.\naxis_info = pd.read_parquet(input_path + 'axis_info.parquet')\n# 3. Sample submission\nsample_submission = pd.read_csv(input_path + 'sample_submission.csv')\n#4. test_star_info\ntest_star_info = pd.read_csv(input_path + 'test_star_info.csv')\n#5. train data sample\ntrain_data_sample = pd.read_csv(input_path + 'train.csv')\n#7. test_star_info\ntrain_star_info = pd.read_csv(input_path + 'train_star_info.csv')\n#8. Wavelength\nwavelength = pd.read_csv(input_path + 'wavelengths.csv')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-07T03:57:35.509679Z","iopub.execute_input":"2025-09-07T03:57:35.509976Z","iopub.status.idle":"2025-09-07T03:57:36.028067Z","shell.execute_reply.started":"2025-09-07T03:57:35.509952Z","shell.execute_reply":"2025-09-07T03:57:36.026896Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Objective\n\nMultilabel regression \n- predict the wavelength and standard deviation for each planet.","metadata":{}},{"cell_type":"markdown","source":"# Processing steps","metadata":{}},{"cell_type":"markdown","source":"## Analog to Digital Conversion\n\nThe pixel voltage is converted to integer numbers by the detector. ADC convertion is used to revert the process using the gain and offset values for the instrument.\n\n----------------------\n- Add additional information.","metadata":{}},{"cell_type":"code","source":"# Define a function to perform analog to doigotal conversion.\n\ndef ADC_convertion(signal, gain, offset):\n    '''\n    Function to convert a signal from Analog to Digital\n    '''\n    signal = signal / gain\n    signal = signal + offset\n\n    return signal","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-07T03:57:39.204768Z","iopub.execute_input":"2025-09-07T03:57:39.205084Z","iopub.status.idle":"2025-09-07T03:57:39.211417Z","shell.execute_reply.started":"2025-09-07T03:57:39.20506Z","shell.execute_reply":"2025-09-07T03:57:39.209892Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Mask hot and dead pixels\n\nIt is a common practice to mask the hot and dead pixel while working with image sensors especially CCD and CMOS detectors. (What are they?)\n\n**What are hot and dead pixels?**\\\n**Hot Pixels** :  Pixels that show high value regardless of the signal.\\\n**Dead Pixels** : Pixels that show very low or 0 value regardless of the signal.\n\n**How to identify the hot and dead pixels?**\n- We can identify the hot pixels using dead frames which are frames captured with the sensor covered. In such a case the hot pixels would continue to appear bright.\n- We can identify the dead pixels using the flat frames which are frames with uniform illumination. In such a case the dead pixels would appear dark.\n\n**Steps used**\n- Hot pixel is identified using the sigma_clip function, pixels that are outliers are identified as the hot pixel.\n- Dead pixel is to be provided to the function. (from where though)\n\n","metadata":{}},{"cell_type":"code","source":"# Masking of hot/dead pixels\n\ndef mask_hot_dead_signal(signal, dead, dark):\n\n    # determine the hot and dead pixels.\n    hot = sigma_clip(dark, sigma=5, maxiters=5).mask\n    \n    # Expand the hot pixel mask to match the number of frames in signal\n    hot = np.tile(hot, (signal.shape[0], 1, 1))  \n    \n    # Expand dead pixel mask too\n    dead = np.tile(dead, (signal.shape[0], 1, 1))  \n    \n    # Apply dead pixel mask\n    signal = np.ma.masked_where(dead, signal)\n    \n    # Apply hot pixel mask\n    signal = np.ma.masked_where(hot, signal)\n    \n    return signal\n    ","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-07T03:57:44.584049Z","iopub.execute_input":"2025-09-07T03:57:44.584388Z","iopub.status.idle":"2025-09-07T03:57:44.591051Z","shell.execute_reply.started":"2025-09-07T03:57:44.584364Z","shell.execute_reply":"2025-09-07T03:57:44.589996Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Linearity Correction\n\nMost sensor systems requires a linearity correction. In an ideal world the measured signal by the detector should be linear to the input signal but in most cases the detector becomes non linear at very low and very high input signals. \n\n**What causes the non linearity?**\n\n**1. Physical Origin**\n- Pixels collect **electrons** in proportion to the number of incoming photons, scaled by the **quantum efficiency**.  \n- **Ideally**:\n- \n  $\n  N_e \\propto N_{\\text{photons}}\n  $\n  \n- **In reality**: Capacitive leakage and readout effects make the pixel response **nonlinear** during charge integration.\n\n---\n\n**2. Nonlinear Response**\n- The measured signal is a polynomial function of the true electrons in the pixel well:\n  \n  $\n  S_\\text{meas} = a_0 + a_1 N_\\text{e⁻} + a_2 N_\\text{e⁻}^2 + a_3 N_\\text{e⁻}^3 + \\dots\n  $\n\n---\n\n**3. Inverse Polynomial Correction**\n- Calibration provides an **inverse polynomial** mapping measured signal back to linear electron counts:\n   \n  $\n  N_\\text{e⁻, corrected} = b_0 + b_1 S_\\text{meas} + b_2 S_\\text{meas}^2 + b_3 S_\\text{meas}^3 + \\dots\n  $\n\n---\n\n","metadata":{}},{"cell_type":"code","source":"def apply_linear_corr(linear_corr,clean_signal):\n    linear_corr = np.flip(linear_corr, axis=0)\n    for x, y in itertools.product(\n                range(clean_signal.shape[1]), range(clean_signal.shape[2])\n            ):\n        poli = np.poly1d(linear_corr[:, x, y])\n        clean_signal[:, x, y] = poli(clean_signal[:, x, y])\n    return clean_signal","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-07T03:57:49.066992Z","iopub.execute_input":"2025-09-07T03:57:49.067332Z","iopub.status.idle":"2025-09-07T03:57:49.074448Z","shell.execute_reply.started":"2025-09-07T03:57:49.067307Z","shell.execute_reply":"2025-09-07T03:57:49.073144Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Dark current subtraction\n\n\n**1. What is Dark Current?**\n- Even with no incoming light, pixels accumulate charge due to **thermal excitations**.  \n- This produces a constant background signal called **dark current**.  \n- It accumulates during the integration time and is **independent of the photon flux**.  \n\n---\n\n**2. Why Correct for Dark Current?**\n- Dark current adds an offset to the true signal.  \n- If uncorrected, it can bias scientific measurements and create artificial structure in the image.  \n- It also enhances hot pixels, which are especially visible in long exposures.\n\n**How to correct for Dark Current?**\n- We can use the provided dark frames for the correction purpose.\n- To get the corrected frames we use the following formula. \n   \n   $\n   Image_\\text{corrected} = Image - (Frame_\\text{dark}*\\Delta t)\n   $\n   \n**Doubts**\n\n---\n- Check the formula and get more clarity","metadata":{}},{"cell_type":"code","source":"def clean_dark(signal, dead, dark, dt):\n\n    dark = np.ma.masked_where(dead, dark)\n    dark = np.tile(dark, (signal.shape[0], 1, 1))\n\n    signal -= dark* dt[:, np.newaxis, np.newaxis]\n    return signal","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-07T03:57:51.902009Z","iopub.execute_input":"2025-09-07T03:57:51.90269Z","iopub.status.idle":"2025-09-07T03:57:51.908368Z","shell.execute_reply.started":"2025-09-07T03:57:51.902657Z","shell.execute_reply":"2025-09-07T03:57:51.907013Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Get Correlated Double Sampling (CDS)","metadata":{}},{"cell_type":"code","source":"def get_cds(signal):\n    cds = signal[:,1::2,:,:] - signal[:,::2,:,:]\n    return cds","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-07T03:57:54.60486Z","iopub.execute_input":"2025-09-07T03:57:54.605258Z","iopub.status.idle":"2025-09-07T03:57:54.61097Z","shell.execute_reply.started":"2025-09-07T03:57:54.605225Z","shell.execute_reply":"2025-09-07T03:57:54.609732Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Flat Field Correction\n\n**What is Flat-Field Correction?**\n\nDetectors (CCD/CMOS arrays) are not perfectly uniform:\n- Some pixels are more sensitive (higher gain), others less.\n- The optical system (lenses, filters, vignetting) can cause uneven illumination.\n\nAs a result, even if the sensor is exposed to a perfectly uniform light source, the image will look uneven.\nFlat-Field Correction removes this non-uniformity.","metadata":{}},{"cell_type":"code","source":"def correct_flat_field(flat,dead, signal):\n    flat = flat.transpose(1, 0)\n    dead = dead.transpose(1, 0)\n    flat = np.ma.masked_where(dead, flat)\n    flat = np.tile(flat, (signal.shape[0], 1, 1))\n    signal = signal / flat\n    return signal","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-07T03:57:56.637405Z","iopub.execute_input":"2025-09-07T03:57:56.637744Z","iopub.status.idle":"2025-09-07T03:57:56.643959Z","shell.execute_reply.started":"2025-09-07T03:57:56.637722Z","shell.execute_reply":"2025-09-07T03:57:56.642556Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Time Binning ","metadata":{}},{"cell_type":"code","source":"def bin_obs(cds_signal,binning):\n    cds_transposed = cds_signal.transpose(0,1,3,2)\n    cds_binned = np.zeros((cds_transposed.shape[0], cds_transposed.shape[1]//binning, cds_transposed.shape[2], cds_transposed.shape[3]))\n    for i in range(cds_transposed.shape[1]//binning):\n        cds_binned[:,i,:,:] = np.sum(cds_transposed[:,i*binning:(i+1)*binning,:,:], axis=1)\n    return cds_binned","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-07T03:58:15.386428Z","iopub.execute_input":"2025-09-07T03:58:15.386744Z","iopub.status.idle":"2025-09-07T03:58:15.392925Z","shell.execute_reply.started":"2025-09-07T03:58:15.386719Z","shell.execute_reply":"2025-09-07T03:58:15.392026Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Display the dataset","metadata":{}},{"cell_type":"code","source":"adc_info","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-07T03:58:19.244011Z","iopub.execute_input":"2025-09-07T03:58:19.244378Z","iopub.status.idle":"2025-09-07T03:58:19.273789Z","shell.execute_reply.started":"2025-09-07T03:58:19.244354Z","shell.execute_reply":"2025-09-07T03:58:19.272457Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"axis_info","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-07T03:58:19.71167Z","iopub.execute_input":"2025-09-07T03:58:19.712077Z","iopub.status.idle":"2025-09-07T03:58:19.731984Z","shell.execute_reply.started":"2025-09-07T03:58:19.712045Z","shell.execute_reply":"2025-09-07T03:58:19.730568Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"wavelength","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-07T03:58:20.51489Z","iopub.execute_input":"2025-09-07T03:58:20.515239Z","iopub.status.idle":"2025-09-07T03:58:20.538539Z","shell.execute_reply.started":"2025-09-07T03:58:20.515212Z","shell.execute_reply":"2025-09-07T03:58:20.537398Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Calibration of Data","metadata":{}},{"cell_type":"code","source":"do_mask = True\ndo_nl_corr = True\ndo_dark = True\ndo_flat = True\ntime_binning = True\n\ncut_inf, cut_sup = 39, 321\nl = cut_sup - cut_inf\n\nAIRS_CH0_clean = np.zeros((1, 11250, 32, l))\nFGS1_clean = np.zeros((1, 135000, 32, 32))\n\nimage_id = 1010375142\n\ndf = pd.read_parquet(input_path + f'/train/{image_id}/AIRS-CH0_signal_0.parquet')\nsignal = df.values.reshape((df.shape[0], 32, 356))\n\ngain = adc_info['AIRS-CH0_adc_gain'].loc[0]\noffset = adc_info['AIRS-CH0_adc_offset'].loc[0]\n\nsignal = ADC_convertion(signal, gain, offset)\n\ndt_airs = axis_info['AIRS-CH0-integration_time'].dropna().values\n\nchopped_signal = signal[:, :, cut_inf:cut_sup]\n\ndel signal, df","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-07T03:58:26.592114Z","iopub.execute_input":"2025-09-07T03:58:26.592512Z","iopub.status.idle":"2025-09-07T03:58:29.660924Z","shell.execute_reply.started":"2025-09-07T03:58:26.592485Z","shell.execute_reply":"2025-09-07T03:58:29.659859Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Read the necessary data for cleaning\n\nflat = pd.read_parquet(input_path + f'train/{image_id}/AIRS-CH0_calibration_0/flat.parquet').values.astype(np.float64).reshape((32, 356))[:, cut_inf:cut_sup]\ndark = pd.read_parquet(input_path + f'train/{image_id}/AIRS-CH0_calibration_0/dark.parquet').values.astype(np.float64).reshape((32, 356))[:, cut_inf:cut_sup]\ndead_airs = pd.read_parquet(input_path + f'train/{image_id}/AIRS-CH0_calibration_0/dead.parquet').values.astype(np.float64).reshape((32, 356))[:, cut_inf:cut_sup]\nlinear_corr = pd.read_parquet(input_path + f'train/{image_id}/AIRS-CH0_calibration_0/linear_corr.parquet').values.astype(np.float64).reshape((6, 32, 356))[:, :, cut_inf:cut_sup]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-07T04:00:22.657944Z","iopub.execute_input":"2025-09-07T04:00:22.65883Z","iopub.status.idle":"2025-09-07T04:00:22.837679Z","shell.execute_reply.started":"2025-09-07T04:00:22.658795Z","shell.execute_reply":"2025-09-07T04:00:22.836532Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"if do_mask:\n    chopped_signal = mask_hot_dead_signal(chopped_signal, dead_airs, dark)\n    AIRS_CH0_clean[0] = chopped_signal\nelse:\n    AIRS_CH0_clean[0] = chopped_signal\n\nif do_nl_corr: \n    linear_corr_signal = apply_linear_corr(linear_corr,AIRS_CH0_clean[0])\n    AIRS_CH0_clean[0] = linear_corr_signal\ndel linear_corr\n\nif do_dark: \n    cleaned_signal = clean_dark(AIRS_CH0_clean[0], dead_airs, dark,dt_airs)\n    AIRS_CH0_clean[0] = cleaned_signal\nelse: \n    pass\ndel dark","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-07T04:02:56.929895Z","iopub.execute_input":"2025-09-07T04:02:56.930232Z","iopub.status.idle":"2025-09-07T04:03:13.623697Z","shell.execute_reply.started":"2025-09-07T04:02:56.930209Z","shell.execute_reply":"2025-09-07T04:03:13.622466Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# FGS\n\ndf = pd.read_parquet(os.path.join(input_path + f'train/{image_id}/FGS1_signal_0.parquet'))\nfgs_signal = df.values.reshape((df.shape[0], 32, 32))\n\nFGS1_gain = adc_info['FGS1_adc_gain'].loc[0]\nFGS1_offset = adc_info['FGS1_adc_offset'].loc[0]\n\nfgs_signal = ADC_convertion(fgs_signal, FGS1_gain, FGS1_offset)\n\ndt_fgs1 = np.ones(len(fgs_signal))*0.1  ## please refer to data documentation for more information\n\nchopped_FGS1 = fgs_signal\n\ndel fgs_signal, df","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-07T04:23:35.235192Z","iopub.execute_input":"2025-09-07T04:23:35.235647Z","iopub.status.idle":"2025-09-07T04:23:36.626183Z","shell.execute_reply.started":"2025-09-07T04:23:35.235619Z","shell.execute_reply":"2025-09-07T04:23:36.625048Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# CLEANING THE DATA: FGS1\nflat = pd.read_parquet(input_path + f'train/{image_id}/FGS1_calibration_0/flat.parquet').values.astype(np.float64).reshape((32, 32))\ndark = pd.read_parquet(input_path + f'train/{image_id}/FGS1_calibration_0/dark.parquet').values.astype(np.float64).reshape((32, 32))\ndead_fgs1 = pd.read_parquet(input_path + f'train/{image_id}/FGS1_calibration_0/dead.parquet').values.astype(np.float64).reshape((32, 32))\nlinear_corr = pd.read_parquet(input_path + f'train/{image_id}/FGS1_calibration_0/linear_corr.parquet').values.astype(np.float64).reshape((6, 32, 32))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-07T04:23:41.552776Z","iopub.execute_input":"2025-09-07T04:23:41.553384Z","iopub.status.idle":"2025-09-07T04:23:41.63398Z","shell.execute_reply.started":"2025-09-07T04:23:41.553351Z","shell.execute_reply":"2025-09-07T04:23:41.632406Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"if do_mask:\n    chopped_FGS1 = mask_hot_dead_signal(chopped_FGS1, dead_fgs1, dark)\n    FGS1_clean[0] = chopped_FGS1\nelse:\n    FGS1_clean[0] = chopped_FGS1\n\nif do_nl_corr: \n    linear_corr_signal = apply_linear_corr(linear_corr,FGS1_clean[0])\n    FGS1_clean[0,:, :, :] = linear_corr_signal\ndel linear_corr\n\nif do_dark: \n    cleaned_signal = clean_dark(FGS1_clean[0], dead_fgs1, dark,dt_fgs1)\n    FGS1_clean[0] = cleaned_signal\nelse: \n    pass\ndel dark ","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-07T04:23:56.909103Z","iopub.execute_input":"2025-09-07T04:23:56.910261Z","iopub.status.idle":"2025-09-07T04:24:19.4965Z","shell.execute_reply.started":"2025-09-07T04:23:56.91021Z","shell.execute_reply":"2025-09-07T04:24:19.494827Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"AIRS_cds = get_cds(AIRS_CH0_clean)\nFGS1_cds = get_cds(FGS1_clean)\n\ndel AIRS_CH0_clean, FGS1_clean","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-07T04:24:44.004997Z","iopub.execute_input":"2025-09-07T04:24:44.005433Z","iopub.status.idle":"2025-09-07T04:24:44.839003Z","shell.execute_reply.started":"2025-09-07T04:24:44.005405Z","shell.execute_reply":"2025-09-07T04:24:44.838041Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Save the data before binning if necessary","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"## (Optional) Time Binning to reduce space\nif time_binning:\n    AIRS_cds_binned = bin_obs(AIRS_cds,binning=30)\n    FGS1_cds_binned = bin_obs(FGS1_cds,binning=30*12)\nelse:\n    AIRS_cds = AIRS_cds.transpose(0,1,3,2) ## this is important to make it consistent for flat fielding, but you can always change it\n    AIRS_cds_binned = AIRS_cds\n    FGS1_cds = FGS1_cds.transpose(0,1,3,2)\n    FGS1_cds_binned = FGS1_cds\n\ndel AIRS_cds, FGS1_cds","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-07T04:26:28.984254Z","iopub.execute_input":"2025-09-07T04:26:28.984629Z","iopub.status.idle":"2025-09-07T04:26:29.167442Z","shell.execute_reply.started":"2025-09-07T04:26:28.984603Z","shell.execute_reply":"2025-09-07T04:26:29.166068Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"flat_airs = pd.read_parquet(input_path + f'train/{image_id}/AIRS-CH0_calibration_0/flat.parquet').values.astype(np.float64).reshape((32, 356))[:, cut_inf:cut_sup]\nflat_fgs = pd.read_parquet(input_path + f'train/{image_id}/FGS1_calibration_0/flat.parquet').values.astype(np.float64).reshape((32, 32))\nif do_flat:\n    corrected_AIRS_cds_binned = correct_flat_field(flat_airs,dead_airs, AIRS_cds_binned[0])\n    AIRS_cds_binned[0] = corrected_AIRS_cds_binned\n    corrected_FGS1_cds_binned = correct_flat_field(flat_fgs,dead_fgs1, FGS1_cds_binned[0])\n    FGS1_cds_binned[0] = corrected_FGS1_cds_binned\nelse:\n    pass","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-07T04:27:33.731051Z","iopub.execute_input":"2025-09-07T04:27:33.731464Z","iopub.status.idle":"2025-09-07T04:27:33.840345Z","shell.execute_reply.started":"2025-09-07T04:27:33.731392Z","shell.execute_reply":"2025-09-07T04:27:33.839343Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Save the sample data\n\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"for i in range(len(AIRS_cds_binned)) : \n    light_curve = AIRS_cds_binned[i,:,:,:].sum(axis=(1,2))\n    plt.plot(light_curve/light_curve.mean(), '-', alpha=0.3)\n\nplt.xlabel('Time (frame index)')\nplt.ylabel('Normalized flux in the frame')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-07T04:28:16.314931Z","iopub.execute_input":"2025-09-07T04:28:16.315303Z","iopub.status.idle":"2025-09-07T04:28:16.778513Z","shell.execute_reply.started":"2025-09-07T04:28:16.315279Z","shell.execute_reply":"2025-09-07T04:28:16.777318Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}