|
| 1 | +{ |
| 2 | + "cells": [ |
| 3 | + { |
| 4 | + "cell_type": "markdown", |
| 5 | + "id": "36d5a662-7a3e-4241-b20d-4d04bf99235a", |
| 6 | + "metadata": {}, |
| 7 | + "source": [ |
| 8 | + "# M1M3 Force Actuator following errors FFT" |
| 9 | + ] |
| 10 | + }, |
| 11 | + { |
| 12 | + "cell_type": "code", |
| 13 | + "execution_count": null, |
| 14 | + "id": "afee1464-e220-4f16-a4c8-cb4f14af9723", |
| 15 | + "metadata": {}, |
| 16 | + "outputs": [], |
| 17 | + "source": [ |
| 18 | + "# Times Square parameters\n", |
| 19 | + "t_start = \"2025-05-27T18:30:15\"\n", |
| 20 | + "t_end = \"2025-05-27T18:30:24\"" |
| 21 | + ] |
| 22 | + }, |
| 23 | + { |
| 24 | + "cell_type": "markdown", |
| 25 | + "id": "0955ef8a-f61a-4ea2-8e79-4d3c3ec8b77c", |
| 26 | + "metadata": {}, |
| 27 | + "source": [ |
| 28 | + "> **Note:** Please select a short time range when running this code. \n", |
| 29 | + "> For example:\n", |
| 30 | + "> ```python\n", |
| 31 | + "> t_start = \"2025-05-27T18:30:15\"\n", |
| 32 | + "> t_end = \"2025-05-27T18:30:24\"\n", |
| 33 | + "> ```\n", |
| 34 | + "> In this example, the time range is only 9 seconds, but the code may still take a while to run. \n", |
| 35 | + "> Selecting longer time intervals (e.g., several minutes or hours) can significantly increase execution time.\n", |
| 36 | + ">\n", |
| 37 | + "> In the future, the code will be optimized to efficiently handle full observation days.\n", |
| 38 | + ">\n", |
| 39 | + "> Additionally, future versions will reduce the number of plots shown by filtering out force actuators with no\n", |
| 40 | + "> significant behavior, helping focus the analysis on potentially problematic components.\n" |
| 41 | + ] |
| 42 | + }, |
| 43 | + { |
| 44 | + "cell_type": "code", |
| 45 | + "execution_count": null, |
| 46 | + "id": "8eb32444-5f61-48ae-a663-3d49c35d1d45", |
| 47 | + "metadata": {}, |
| 48 | + "outputs": [], |
| 49 | + "source": [ |
| 50 | + "import matplotlib.pyplot as plt\n", |
| 51 | + "import numpy as np\n", |
| 52 | + "import os\n", |
| 53 | + "import argparse\n", |
| 54 | + "from astropy.time import Time, TimeDelta" |
| 55 | + ] |
| 56 | + }, |
| 57 | + { |
| 58 | + "cell_type": "code", |
| 59 | + "execution_count": null, |
| 60 | + "id": "e1e1d9b1-997f-4c35-91f3-b295026633c9", |
| 61 | + "metadata": {}, |
| 62 | + "outputs": [], |
| 63 | + "source": [ |
| 64 | + "from lsst.summit.utils.tmaUtils import TMAEventMaker\n", |
| 65 | + "from lsst.summit.utils.efdUtils import EfdClient, getEfdData, makeEfdClient, getDayObsEndTime, getDayObsStartTime\n", |
| 66 | + "from lsst.ts.xml.tables.m1m3 import FATable" |
| 67 | + ] |
| 68 | + }, |
| 69 | + { |
| 70 | + "cell_type": "code", |
| 71 | + "execution_count": null, |
| 72 | + "id": "3a0d6e99-ab66-45ab-b7b3-49b2ffbcdfc0", |
| 73 | + "metadata": {}, |
| 74 | + "outputs": [], |
| 75 | + "source": [ |
| 76 | + "# Create an EFD client instance\n", |
| 77 | + "client = makeEfdClient()\n", |
| 78 | + "\n", |
| 79 | + "# Define the start and end time\n", |
| 80 | + "t_start = Time(t_start)\n", |
| 81 | + "t_end = Time(t_end)\n", |
| 82 | + "\n", |
| 83 | + "main(t_start, t_end)\n" |
| 84 | + ] |
| 85 | + }, |
| 86 | + { |
| 87 | + "cell_type": "code", |
| 88 | + "execution_count": null, |
| 89 | + "id": "544289e3-35b4-40fd-9311-f510cc89efa4", |
| 90 | + "metadata": {}, |
| 91 | + "outputs": [], |
| 92 | + "source": [ |
| 93 | + "def loop_over_actuators(client, topic, nb_actuators, t_start, t_end):\n", |
| 94 | + " print(f\"Processing {topic}\")\n", |
| 95 | + "\n", |
| 96 | + " plot_directory = \"./plots/\"\n", |
| 97 | + " if not os.path.exists(plot_directory):\n", |
| 98 | + " os.makedirs(plot_directory)\n", |
| 99 | + " FA_error = [f\"{topic}{i}\" for i in range(nb_actuators)]\n", |
| 100 | + "\n", |
| 101 | + " if \"secondary\" in topic:\n", |
| 102 | + " secondary_actuator_id = np.array([])\n", |
| 103 | + " for i in range(len(FATable)):\n", |
| 104 | + " if FATable[i].s_index is not None:\n", |
| 105 | + " secondary_actuator_id = np.append(\n", |
| 106 | + " secondary_actuator_id, FATable[i].actuator_id\n", |
| 107 | + " )\n", |
| 108 | + " secondary_actuator_id = secondary_actuator_id.astype(int)\n", |
| 109 | + " \n", |
| 110 | + " for fa in range(nb_actuators):\n", |
| 111 | + " if fa % 10 == 0:\n", |
| 112 | + " print(f\"{fa}/{nb_actuators}\")\n", |
| 113 | + " df = getEfdData(\n", |
| 114 | + " client,\n", |
| 115 | + " \"lsst.sal.MTM1M3.forceActuatorData\",\n", |
| 116 | + " columns=FA_error,\n", |
| 117 | + " begin=t_start,\n", |
| 118 | + " end=t_end,\n", |
| 119 | + " )\n", |
| 120 | + " \n", |
| 121 | + " dt = (df[f\"{topic}0\"].index[1] - df[f\"{topic}0\"].index[0]).total_seconds()\n", |
| 122 | + " freqs = np.fft.fftfreq(len(df), d=dt)\n", |
| 123 | + " positive_mask = freqs > 0\n", |
| 124 | + " fft_frequency = freqs[positive_mask]\n", |
| 125 | + " fft_result = np.fft.fft(df.values, axis=0)\n", |
| 126 | + " fft_magnitudes = np.abs(fft_result[positive_mask, :])\n", |
| 127 | + " plt.figure(figsize=(10, 5))\n", |
| 128 | + " \n", |
| 129 | + " if \"primary\" in topic:\n", |
| 130 | + " label = FATable[fa].actuator_id\n", |
| 131 | + " else:\n", |
| 132 | + " label = secondary_actuator_id[fa]\n", |
| 133 | + " \n", |
| 134 | + " plt.plot(\n", |
| 135 | + " fft_frequency, fft_magnitudes[:, fa], label=f\"Primary actuator {label}\"\n", |
| 136 | + " )\n", |
| 137 | + " plt.title(f\"Power spectrum from {t_start} to {t_end}\")\n", |
| 138 | + " plt.xlabel(\"Frequency [Hz]\")\n", |
| 139 | + " plt.ylabel(\"Magnitude\")\n", |
| 140 | + " plt.legend()\n", |
| 141 | + " plt.show()\n", |
| 142 | + "\n", |
| 143 | + " #if \"primary\" in topic:\n", |
| 144 | + " # plt.savefig(f\"{plot_directory}PA_{FATable[fa].actuator_id}.png\")\n", |
| 145 | + " #else:\n", |
| 146 | + " # plt.savefig(f\"{plot_directory}SA_{secondary_actuator_id[fa]}.png\")\n", |
| 147 | + "\n", |
| 148 | + " \n", |
| 149 | + "def main(t_start, t_end):\n", |
| 150 | + "\n", |
| 151 | + " loop_over_actuators(\n", |
| 152 | + " client, \"primaryCylinderFollowingError\", len(FATable), t_start, t_end\n", |
| 153 | + " )\n", |
| 154 | + "\n", |
| 155 | + " loop_over_actuators(\n", |
| 156 | + " client, \"secondaryCylinderFollowingError\", 112, t_start, t_end\n", |
| 157 | + " )\n", |
| 158 | + " " |
| 159 | + ] |
| 160 | + } |
| 161 | + ], |
| 162 | + "metadata": { |
| 163 | + "kernelspec": { |
| 164 | + "display_name": "LSST", |
| 165 | + "language": "python", |
| 166 | + "name": "lsst" |
| 167 | + }, |
| 168 | + "language_info": { |
| 169 | + "codemirror_mode": { |
| 170 | + "name": "ipython", |
| 171 | + "version": 3 |
| 172 | + }, |
| 173 | + "file_extension": ".py", |
| 174 | + "mimetype": "text/x-python", |
| 175 | + "name": "python", |
| 176 | + "nbconvert_exporter": "python", |
| 177 | + "pygments_lexer": "ipython3", |
| 178 | + "version": "3.12.10" |
| 179 | + } |
| 180 | + }, |
| 181 | + "nbformat": 4, |
| 182 | + "nbformat_minor": 5 |
| 183 | +} |
0 commit comments