diff --git a/M2_analysis_notebooks/.ipynb_checkpoints/LVV-T3034_M2_analysis_CL_breakout_test-single-window-checkpoint.ipynb b/M2_analysis_notebooks/.ipynb_checkpoints/LVV-T3034_M2_analysis_CL_breakout_test-single-window-checkpoint.ipynb new file mode 100644 index 0000000..786eb86 --- /dev/null +++ b/M2_analysis_notebooks/.ipynb_checkpoints/LVV-T3034_M2_analysis_CL_breakout_test-single-window-checkpoint.ipynb @@ -0,0 +1,934 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# M2 forces vs. M2 Closed-loop breakout test" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Readme\n", + "\n", + "This notebook analyzes the evolutions of the measured forces for the tangent and axial actuators during a break-out of the M2 closed-loop during the ramp-up of the TMA slewing speed test campaing. \n", + "Modify the EFD time windows to run again the script on different datasets.\n", + "\n", + "Enter manually the timestamp of the testing window. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import Modules\n", + "\n", + "This notebook needs to setup the **ts_m2com** and **ts_aos_utilsts** under the **notebooks/.user_setups**, which depends on the **ts_tcpip**.\n", + "You also need to have **ts_mtm2** under the **WORK/** directory to read the confiugration files to do the analysis." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%matplotlib inline\n", + "%matplotlib widget \n", + "import matplotlib.pyplot as plt\n", + "import math\n", + "from pathlib import Path\n", + "import numpy as np\n", + "from sklearn.linear_model import LinearRegression\n", + "from astropy.time import Time\n", + "import pandas as pd\n", + "import lsst_efd_client\n", + "\n", + "from lsst.ts.m2com.mock import MockModel\n", + "from lsst.ts.m2com import MockControlClosedLoop\n", + "import tabulate \n", + "from lsst.ts.aos.utils import DiagnosticsM2, EfdName" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## TMA slewing intervals" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# M2 CL break-out intervals - TMA Slewing intervals\n", + "\n", + "slew_intervals = {\n", + " 0: [\n", + " # 1% el 1% az\n", + " Time(\"2024-11-06T08:42:00\",scale=\"utc\", format=\"isot\"),\n", + " Time(\"2024-11-06T08:45:18\",scale=\"utc\", format=\"isot\"),\n", + " ],\n", + "}\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Set title plots" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# create title slewing speed\n", + "title = \"TMA (1%,1%) max speed, M2 with glass\"\n", + "location =\"best\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Functions declaration" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "async def query_data(\n", + " diagnostics_m2: DiagnosticsM2,\n", + " control_closed_loop: MockControlClosedLoop,\n", + " time_start: Time,\n", + " time_end: Time,\n", + ") -> None:\n", + " \"\"\"\n", + " Query the data.\n", + "\n", + " # functions declaration can be found here:\n", + " # https://github.com/lsst-ts/ts_aos_utils/blob/feature/m2power/python/lsst/ts/aos/utils/diagnostics_m2.py\n", + " Parameters\n", + " ----------\n", + " diagnostics_m2 : `lsst.ts.aos.utils.DiagnosticsM2`\n", + " M2 diagnostics instance.\n", + " control_closed_loop : `lsst.ts.m2.com.MockControlClosedLoop`\n", + " Mock control closed loop instance.\n", + " time_start : `astropy.time.core.Time`\n", + " Start time.\n", + " time_end : `astropy.time.core.Time`\n", + " End time.\n", + " \"\"\"\n", + "\n", + " # Get the x, y position of actuators\n", + " xy_actuators = diagnostics_m2.get_xy_actuators(control_closed_loop)\n", + "\n", + " # Query data\n", + " data_ims, time_operation_ims = await diagnostics_m2.get_data_position(\n", + " \"positionIMS\", time_start, time_end\n", + " )\n", + "\n", + " data_collected_axial, data_collected_tangent = await diagnostics_m2.get_data_force(\n", + " time_start, time_end\n", + " )\n", + "\n", + " data_power_status, time_operation = await diagnostics_m2.get_data_power_status(\n", + " time_start, time_end\n", + " )\n", + "\n", + " data_inclinometer = await diagnostics_m2.get_data_zenith_angle(\n", + " time_start, time_end\n", + " )\n", + "\n", + " data_tangent_force_error = await diagnostics_m2.get_data_force_error_tangent(\n", + " time_start, time_end\n", + " )\n", + "\n", + " data_net_moment = await diagnostics_m2.get_data_net_moment(\n", + " time_start, time_end\n", + " )\n", + "\n", + " return xy_actuators, data_ims, data_collected_axial, data_collected_tangent, data_power_status, data_inclinometer, data_net_moment" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def actuator_plot(\n", + " diagnostics_m2,\n", + " control_closed_loop,\n", + " actuators_groups,\n", + " group,\n", + " data_collected_tangent,\n", + " full_stream,\n", + " face,\n", + " data_ims,\n", + " merged_vectors,\n", + " data_inclinometer,\n", + " key,\n", + " m2_cl_status_breakout,\n", + " title,\n", + "):\n", + "\n", + " \n", + "\n", + " \n", + " \n", + " #************************************\n", + " #\n", + " # Set UTC x axis metrics\n", + " #\n", + " #************************************\n", + "\n", + "\n", + " # time stamp closed-loop breakout event\n", + " \n", + " t1 = m2_cl_status_breakout.index[0]\n", + " print(t1)\n", + "\n", + " td = pd.Timedelta(\"0.05 sec\")\n", + "\n", + " cl = np.where(abs(t1 - merged_vectors.index) < td)\n", + "\n", + " t2 = merged_vectors.index[cl]\n", + "\n", + " time_ol_event = t2[0]\n", + " \n", + " print(time_ol_event)\n", + "\n", + " \n", + " time_ol_event = m2_cl_status_breakout.index[0]\n", + " asse = merged_vectors[\"measured0\"]\n", + "\n", + " xx1 = [asse.index[0],time_ol_event, asse.index[-1]]\n", + " xx2 = [asse.index[0], time_ol_event]\n", + " \n", + " tempo = xx1\n", + " tempo2 = xx2\n", + " \n", + " tempo = pd.to_datetime(tempo, format='%Y-%m-%d %H:%M:%S.%f').strftime('%Y-%m-%d %H:%M')\n", + " tempo2 = pd.to_datetime(tempo2, format='%Y-%m-%d %H:%M:%S.%f').strftime('%H:%M:%S')\n", + "\n", + " cl1 = pd.to_datetime(time_ol_event, format='%Y-%m-%d %H:%M:%S.%f').strftime('%Y-%m-%d %H:%M')\n", + " cl2 = pd.to_datetime(time_ol_event, format='%Y-%m-%d %H:%M:%S.%f').strftime('%H:%M:%S')\n", + "\n", + "\n", + " newx2 = [tempo2[0],cl2]\n", + " newx1 = [tempo[0],cl1,tempo[-1]]\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + " #************************************\n", + " #\n", + " # PLOT measured tangent forces\n", + " #\n", + " #************************************\n", + "\n", + " font = {\n", + " \"family\": \"serif\",\n", + " \"color\": \"black\",\n", + " \"weight\": \"normal\",\n", + " \"size\": 10,\n", + " }\n", + "\n", + " hatF = \"$\\overline{F}), N$\"\n", + "\n", + " \n", + " fig = plt.figure()\n", + " fig.subplots_adjust(hspace=0.9, wspace=0.9)\n", + " \n", + " n = 6\n", + " fig.suptitle(title)\n", + "\n", + " for idx in range(n):\n", + " ax = fig.add_subplot(3, 2, idx + 1)\n", + " ax.plot(merged_vectors[f\"measured{idx}\"],color=\"black\")\n", + " ax.set_xticks(xx2, newx2)\n", + " ax.axhline(4893, color=\"orange\", label=\"+CL Max F\")\n", + " ax.axhline(6227, color=\"red\", label=\"+OL Max F\")\n", + " ax.axhline(-4893, color=\"orange\")\n", + " ax.axhline(-6227, color=\"red\")\n", + " ax.axvline(time_ol_event, label = 'CL breakout', color=\"black\", linewidth = \"0.5\")\n", + "\n", + " num_act = actuators_groups[idx] + 1\n", + " ax.set_title(\"A%i\" % (idx + 1), fontdict=font)\n", + " ax.set_ylabel(\"Meas. F, N\", fontdict=font)\n", + "\n", + "\n", + " if idx == 1:\n", + " ax.set_ylim([-7000, 7000])\n", + " ax.legend(loc=\"upper right\", fontsize=\"8\")\n", + " \n", + " elif idx == 2:\n", + " ax.set_ylim([-7000, 7000])\n", + "\n", + " elif idx == 4:\n", + " ax.set_ylim([-7000, 7000])\n", + " ax.set_xlabel(\"UTC\", fontdict=font)\n", + "\n", + " elif idx == 5:\n", + " ax.set_ylim([-7000, 7000])\n", + " ax.set_xlabel(\"UTC\", fontdict=font)\n", + "\n", + "\n", + " \n", + " # ********************************************\n", + " #\n", + " # ISM RBM\n", + " #\n", + " # ********************************************\n", + "\n", + "\n", + "\n", + " font = {\n", + " \"family\": \"serif\",\n", + " \"color\": \"black\",\n", + " \"weight\": \"normal\",\n", + " \"size\": 9,\n", + " }\n", + "\n", + " fig = plt.figure(figsize=(10,8))\n", + "\n", + " ax1 = plt.subplot(231)\n", + " ax1.plot(merged_vectors[\"x\"])\n", + " ax1.set_ylabel(\"IMS x, \\u03BCm\", fontdict=font)\n", + " ax1.axvline(time_ol_event, label = 'CL breakout', color=\"black\", linewidth = \"0.5\")\n", + " ax1.set_xticks(xx2, newx2)\n", + " ax1.legend(loc=\"best\", fontsize=\"8\")\n", + " \n", + " ax2 = plt.subplot(232)\n", + " ax2.plot(merged_vectors[\"y\"])\n", + " ax2.set_ylabel(\"IMS y, \\u03BCm\", fontdict=font)\n", + " ax2.axvline(time_ol_event, color=\"black\", linewidth = \"0.5\")\n", + " ax2.set_xticks(xx2, newx2)\n", + "\n", + " ax3 = plt.subplot(233)\n", + " ax3.plot(merged_vectors[\"z\"])\n", + " ax3.set_ylabel(\"IMS z, \\u03BCm\", fontdict=font)\n", + " ax3.axvline(time_ol_event, color=\"black\", linewidth = \"0.5\")\n", + " ax3.set_xticks(xx2, newx2)\n", + "\n", + " ax4 = plt.subplot(234)\n", + " ax4.plot(merged_vectors[\"xRot\"])\n", + " ax4.set_ylabel(\"IMS xRot, arcsec\", fontdict=font)\n", + " ax4.set_xlabel(\"UTC\", fontdict=font)\n", + " ax4.axvline(time_ol_event, color=\"black\", linewidth = \"0.5\")\n", + " ax4.set_xticks(xx2, newx2)\n", + " \n", + " ax5 = plt.subplot(235)\n", + " ax5.plot(merged_vectors[\"yRot\"])\n", + " ax5.set_ylabel(\"IMS yRot, arcsec\", fontdict=font)\n", + " ax5.set_xlabel(\"UTC\", fontdict=font)\n", + " ax5.axvline(time_ol_event, color=\"black\", linewidth = \"0.5\")\n", + " ax5.set_xticks(xx2, newx2)\n", + " \n", + " \n", + " ax6 = plt.subplot(236)\n", + " ax6.plot(merged_vectors[\"zRot\"])\n", + " ax6.set_ylabel(\"IMS zRot, arcsec\", fontdict=font)\n", + " ax6.set_xlabel(\"UTC\", fontdict=font)\n", + " ax6.axvline(time_ol_event, color=\"black\", linewidth = \"0.5\")\n", + " ax6.set_xticks(xx2, newx2)\n", + " \n", + " fig.suptitle(title)\n", + "\n", + " fig.tight_layout()\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + " # ********************************************\n", + " #\n", + " # Sum & Weight force errors \n", + " #\n", + " # ********************************************\n", + "\n", + "\n", + " font = {\n", + " \"family\": \"serif\",\n", + " \"color\": \"black\",\n", + " \"weight\": \"normal\",\n", + " \"size\": 10,\n", + " }\n", + "\n", + "\n", + " fig = plt.figure()\n", + "\n", + " ax1 = plt.subplot(111)\n", + " fig.suptitle(title)\n", + " ax1.plot(merged_vectors[\"force0\"],label=\"A1 $F_{error}$\")\n", + " ax1.plot(merged_vectors[\"force1\"],label=\"A2 $F_{error}$\")\n", + " ax1.plot(merged_vectors[\"force2\"],label=\"A3 $F_{error}$\")\n", + " ax1.plot(merged_vectors[\"force3\"],label=\"A4 $F_{error}$\")\n", + " ax1.plot(merged_vectors[\"force4\"],label=\"A5 $F_{error}$\")\n", + " ax1.plot(merged_vectors[\"force5\"],label=\"A6 $F_{error}$\")\n", + " ax1.plot(merged_vectors[\"sum\"],label=\"Sum $F_{error} < 1000N$\")\n", + " ax1.plot(merged_vectors[\"weight\"],label=\"Weight $F_{error}$\")\n", + "\n", + " ax1.axvline(time_ol_event, label = 'CL breakout', color=\"black\", linewidth = \"0.5\")\n", + " \n", + " ax1.axhline(1000, linestyle = \"dashed\", color=\"red\")\n", + " ax1.axhline(-1000, linestyle = \"dashed\", color=\"red\")\n", + " ax1.axhline(2000, color=\"red\")\n", + " ax1.axhline(-2000, color=\"red\")\n", + " ax1.set_xticks(xx1,newx1)\n", + " ax1.set_ylabel(\"Tangent force errors, N\", fontdict=font)\n", + " ax1.set_xlabel(\"UTC\", fontdict=font)\n", + " ax1.legend(loc=\"lower right\", fontsize=\"8\")\n", + " ax1.set_title(\"TMA\", fontdict=font)\n", + " \n", + " \n", + " fig.tight_layout()\n", + "\n", + " \n", + "\n", + "\n", + " font = {\n", + " \"family\": \"serif\",\n", + " \"color\": \"black\",\n", + " \"weight\": \"normal\",\n", + " \"size\": 10,\n", + " }\n", + "\n", + " fig = plt.figure()\n", + "\n", + " fig.suptitle(title)\n", + " ax1 = plt.subplot(111)\n", + " lns1 = ax1.plot(merged_vectors[\"inclinometerProcessed\"],label=\"Elevation\", color = \"black\")\n", + " ax1.set_ylabel(\"TMA Elevation, deg\", fontdict=font)\n", + " ax2 = ax1.twinx()\n", + " lns3 = ax1.axvline(time_ol_event, label = 'CL breakout', color=\"black\", linewidth = \"0.5\")\n", + " lns2 = ax2.plot(merged_vectors[\"actualPosition\"],label=\"Azimuth\", color = \"green\");\n", + " ax2.set_ylabel(\"TMA Azimuth, deg\", fontdict=font)\n", + " lns = lns1+lns2+[lns3]\n", + " labs = [l.get_label() for l in lns]\n", + " ax1.legend(lns, labs, loc = \"center right\")\n", + " ax1.set_xticks(xx1,newx1)\n", + " ax1.set_xlabel(\"UTC\", fontdict=font)\n", + " fig.tight_layout()\n", + "\n", + " " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def actuator_plot_axial(\n", + " diagnostics_m2,\n", + " control_closed_loop,\n", + " actuators_groups,\n", + " group,\n", + " data_collected_axial,\n", + " full_stream,\n", + " face,\n", + " data_ims,\n", + " merged_vectors,\n", + " data_inclinometer,\n", + " key,\n", + " m2_cl_status_breakout,\n", + " title,\n", + "):\n", + "\n", + "\n", + " #************************************\n", + " #\n", + " # Set UTC x axis metrics\n", + " #\n", + " #************************************\n", + "\n", + " # time stamp closed-loop breakout event\n", + " \n", + " t1 = m2_cl_status_breakout.index[0]\n", + " print(t1)\n", + "\n", + " td = pd.Timedelta(\"0.05 sec\")\n", + "\n", + " cl = np.where(abs(t1 - merged_vectors.index) < td)\n", + "\n", + " t2 = merged_vectors.index[cl]\n", + "\n", + " time_ol_event = t2[0]\n", + " \n", + " print(time_ol_event)\n", + "\n", + " \n", + " time_ol_event = m2_cl_status_breakout.index[0]\n", + " asse = merged_vectors[\"measured0\"]\n", + "\n", + " xx1 = [asse.index[0],time_ol_event, asse.index[-1]]\n", + " xx2 = [asse.index[0], time_ol_event]\n", + " \n", + " tempo = xx1\n", + " tempo2 = xx2\n", + " \n", + " tempo = pd.to_datetime(tempo, format='%Y-%m-%d %H:%M:%S.%f').strftime('%Y-%m-%d %H:%M')\n", + " tempo2 = pd.to_datetime(tempo2, format='%Y-%m-%d %H:%M:%S.%f').strftime('%H:%M:%S')\n", + "\n", + " cl1 = pd.to_datetime(time_ol_event, format='%Y-%m-%d %H:%M:%S.%f').strftime('%Y-%m-%d %H:%M')\n", + " cl2 = pd.to_datetime(time_ol_event, format='%Y-%m-%d %H:%M:%S.%f').strftime('%H:%M:%S')\n", + "\n", + "\n", + " newx2 = [tempo2[0],cl2]\n", + " newx1 = [tempo[0],cl1,tempo[-1]]\n", + "\n", + "\n", + " \n", + "\n", + " #************************************\n", + " #\n", + " # PLOT measured axial forces\n", + " #\n", + " #************************************\n", + "\n", + " font = {\n", + " \"family\": \"serif\",\n", + " \"color\": \"black\",\n", + " \"weight\": \"normal\",\n", + " \"size\": 10,\n", + " }\n", + "\n", + " hatF = \"$\\overline{F}), N$\"\n", + " \n", + " fig = plt.figure()\n", + " \n", + " n = 72\n", + " fig.suptitle(title)\n", + " ax = fig.add_subplot(1, 1, 1)\n", + " \n", + " for idx in range(n):\n", + " ax.plot(merged_vectors[f\"measured{idx}\"])\n", + " ax.set_xticks(xx1,newx1)\n", + " ax.axhline(444, color=\"orange\", label=\"+CL Max F\")\n", + " ax.axhline(666, color=\"red\", label=\"+OL Max F\")\n", + " ax.axhline(-444, color=\"orange\")\n", + " ax.axhline(-666, color=\"red\") \n", + " ax.axvline(time_ol_event, label = 'CL breakout', color=\"black\", linewidth = \"0.5\")\n", + " ax.set_ylabel(\"Measured axial forces, N\", fontdict=font)\n", + " ax.set_xlabel(\"UTC\", fontdict=font)\n", + " ax.legend(loc=\"upper right\", fontsize=\"8\")\n", + "\n", + " " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def add_force_error(data: pd.DataFrame) -> pd.DataFrame:\n", + " \n", + "\n", + " df = data.copy()\n", + " cols = [\"force0\", \"force1\", \"force2\", \"force3\", \"force4\", \"force5\", \"weight\", \"sum\"]\n", + "\n", + "\n", + " for i, row in enumerate(data.iterrows()):\n", + " if abs(row[1][\"inclinometerRaw\"]) > 360:\n", + " c = 1\n", + " searching = True\n", + " while searching:\n", + " eval_angle = data.loc[data.index[i - c], \"inclinometerRaw\"]\n", + " if abs(eval_angle) < 360:\n", + " angle = eval_angle\n", + " searching = False\n", + " else:\n", + " c += 1\n", + " else:\n", + " angle = row[1][\"inclinometerRaw\"]\n", + "\n", + " mock = MockModel()\n", + " angle = mock.control_open_loop.correct_inclinometer_angle(angle)\n", + " mock.control_open_loop.inclinometer_angle = angle\n", + "\n", + " tangent_force_error = mock._calculate_force_error_tangent(\n", + " np.array(\n", + " [\n", + " row[1][\"measured0\"],\n", + " row[1][\"measured1\"],\n", + " row[1][\"measured2\"],\n", + " row[1][\"measured3\"],\n", + " row[1][\"measured4\"],\n", + " row[1][\"measured5\"],\n", + " ]\n", + " )\n", + " )\n", + "\n", + " df.loc[row[0], cols[:-2]] = tangent_force_error[\"force\"]\n", + " df.loc[row[0], cols[-2]] = tangent_force_error[\"weight\"]\n", + " df.loc[row[0], cols[-1]] = tangent_force_error[\"sum\"]\n", + "\n", + " return df" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "async def get_merge_query(\n", + " efd_client: lsst_efd_client.EfdClient,\n", + " topics: list,\n", + " start_time: Time,\n", + " end_time: Time,\n", + " tolerance=None,\n", + " direction: str = None,\n", + "):\n", + " query_df = list()\n", + " calculate_force_error = False\n", + " for topic in topics:\n", + " topic_fields = await efd_client.get_fields(topic)\n", + " query = efd_client.build_time_range_query(\n", + " topic, topic_fields, start_time, end_time\n", + " )\n", + " data_query = await efd_client.influx_client.query(query)\n", + " if len(data_query) == 0 and topic == \"lsst.sal.MTM2.forceErrorTangent\":\n", + " print(f\"{topic} is not present, try to calculate it.\")\n", + " calculate_force_error = True\n", + " elif len(data_query) == 0:\n", + " print(f\"{topic} is not present.\")\n", + " else:\n", + " query_df.append(data_query)\n", + " if len(query_df) == 1:\n", + " return query_df[0]\n", + " elif len(query_df) == 0:\n", + " print(\"No Dataframe retrieve\")\n", + " return query_df\n", + " query_df.sort(key=lambda el: len(el), reverse=True)\n", + " merge_df = query_df[0].copy()\n", + " for i, df in enumerate(query_df[1:]):\n", + " col_left = topics[i].split(\".\")[-1]\n", + " col_right = topics[i + 1].split(\".\")[-1]\n", + " if tolerance is None and direction is None:\n", + " merge_df = lsst_efd_client.rendezvous_dataframes(\n", + " merge_df,\n", + " df,\n", + " direction=\"nearest\",\n", + " suffixes=[f\"_{col_left}\", f\"_{col_right}\"],\n", + " )\n", + " elif tolerance is None and direction is not None:\n", + " merge_df = lsst_efd_client.rendezvous_dataframes(\n", + " merge_df,\n", + " df,\n", + " direction=direction,\n", + " suffixes=[f\"_{col_left}\", f\"_{col_right}\"],\n", + " )\n", + " elif tolerance is not None and direction is None:\n", + " merge_df = lsst_efd_client.rendezvous_dataframes(\n", + " merge_df,\n", + " df,\n", + " direction=\"nearest\",\n", + " tolerance=tolerance,\n", + " suffixes=[f\"_{col_left}\", f\"_{col_right}\"],\n", + " )\n", + " else:\n", + " merge_df = lsst_efd_client.rendezvous_dataframes(\n", + " merge_df,\n", + " df,\n", + " direction=direction,\n", + " tolerance=tolerance,\n", + " suffixes=[f\"_{col_left}\", f\"_{col_right}\"],\n", + " )\n", + " if calculate_force_error:\n", + " merge_df = add_force_error(merge_df)\n", + " return merge_df\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def spot_cl_breakout_event(\n", + " merged_vectors,\n", + " key,\n", + "):\n", + " \n", + " \n", + " # find M2 closed loop break-out time\n", + "\n", + " \n", + " useful_index = []\n", + " \n", + " \n", + " # find M2 closed loop break-out time \n", + " #if m2_cl_status.shape[0] == 0:\n", + " # continue\n", + "\n", + " for i, status in enumerate(m2_cl_status[\"mode\"]):\n", + " print(status)\n", + " # find open loop event = 3\n", + " if (status == 3):\n", + " useful_index.append(i)\n", + "\n", + " if len(useful_index) != 0:\n", + " print(\"Timestamp M2 CL breakout:\")\n", + " print(useful_index[0], m2_cl_status.index[useful_index[0]])\n", + "\n", + " m2_cl_status_breakout = m2_cl_status.index[useful_index[0]]\n", + " \n", + " return useful_index, m2_cl_status_breakout" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Instantiate the MockControlClosedLoop" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "config_path = Path.home() / \"WORK\" / \"ts_mtm2\" / \"config\" / \"parameter_files\"\n", + "filepath_cell_geom = Path.home() / \"WORK\" / \"ts_mtm2\" / \"config\" / \"cellGeom.json\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "control_closed_loop = MockControlClosedLoop()\n", + "control_closed_loop.load_file_cell_geometry(filepath_cell_geom)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Instantiate the DiagnosticsM2 Class\n", + "\n", + "Notice that the UTC time is used when doing the query." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "diagnostics_m2 = DiagnosticsM2(efd_name=EfdName.Usdf)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Instatiate EFD client" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "efd_client = lsst_efd_client.EfdClient(efd_name=\"usdf_efd\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Tangent actuators" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "actuators_groups = np.array([72, 73, 74, 75, 76, 77])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "\n", + "# Plots for tangent actuators\n", + "\n", + "for key, val in slew_intervals.items():\n", + " time_start = val[0]\n", + " time_end = val[1]\n", + "\n", + "\n", + " (\n", + " xy_actuators,\n", + " data_ims, \n", + " data_collected_axial, \n", + " data_collected_tangent, \n", + " data_power_status, \n", + " data_inclinometer,\n", + " data_net_moment,\n", + " ) = await query_data(diagnostics_m2, control_closed_loop, time_start, time_end)\n", + "\n", + " \n", + "\n", + " merged_vectors = await get_merge_query(\n", + " efd_client,\n", + " [\n", + " \"lsst.sal.MTM2.tangentEncoderPositions\", \n", + " \"lsst.sal.MTM2.tangentForce\",\n", + " \"lsst.sal.MTM2.forceErrorTangent\",\n", + " \"lsst.sal.MTM2.positionIMS\",\n", + " \"lsst.sal.MTM2.displacementSensors\",\n", + " \"lsst.sal.MTM2.zenithAngle\",\n", + " \"lsst.sal.MTM2.forceBalance\",\n", + " \"lsst.sal.MTMount.azimuth\",\n", + " ],\n", + " time_start,\n", + " time_end,\n", + " \n", + " )\n", + "\n", + " \n", + " m2_cl_status_breakout = await efd_client.select_time_series(\n", + " \"lsst.sal.MTM2.logevent_closedLoopControlMode\",\n", + " fields=[\"mode\"],\n", + " start=time_start,\n", + " end=time_end) \n", + "\n", + "\n", + "\n", + " full_stream = len(data_collected_tangent[\"measured\"])\n", + " \n", + " actuator_plot(\n", + " diagnostics_m2,\n", + " control_closed_loop,\n", + " actuators_groups,\n", + " key,\n", + " data_collected_tangent,\n", + " full_stream,\n", + " \"down\",\n", + " data_ims,\n", + " merged_vectors,\n", + " data_inclinometer,\n", + " key,\n", + " m2_cl_status_breakout,\n", + " title,\n", + " )\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "\n", + "# Plots for axial actuators\n", + "\n", + "for key, val in slew_intervals.items():\n", + " time_start = val[0]\n", + " time_end = val[1]\n", + "\n", + "\n", + " (\n", + " xy_actuators,\n", + " data_ims, \n", + " data_collected_axial, \n", + " data_collected_tangent, \n", + " data_power_status, \n", + " data_inclinometer,\n", + " data_net_moment,\n", + " ) = await query_data(diagnostics_m2, control_closed_loop, time_start, time_end)\n", + "\n", + " \n", + "\n", + " merged_vectors = await get_merge_query(\n", + " efd_client,\n", + " [\n", + " \"lsst.sal.MTM2.axialEncoderPositions\", \n", + " \"lsst.sal.MTM2.axialForce\",\n", + " \"lsst.sal.MTM2.forceErrorTangent\",\n", + " \"lsst.sal.MTM2.zenithAngle\",\n", + " \"lsst.sal.MTM2.forceBalance\",\n", + " \"lsst.sal.MTMount.azimuth\",\n", + " ],\n", + " time_start,\n", + " time_end,\n", + " \n", + " )\n", + "\n", + " full_stream = len(data_collected_axial[\"measured\"])\n", + " \n", + " actuator_plot_axial(\n", + " diagnostics_m2,\n", + " control_closed_loop,\n", + " actuators_groups,\n", + " key,\n", + " data_collected_axial,\n", + " full_stream,\n", + " \"down\",\n", + " data_ims,\n", + " merged_vectors,\n", + " data_inclinometer,\n", + " key,\n", + " m2_cl_status_breakout,\n", + " title,\n", + " )\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "LSST", + "language": "python", + "name": "lsst" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.9" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/M2_analysis_notebooks/LVV-T3034_M2_analysis_CL_breakout_test-single-window.ipynb b/M2_analysis_notebooks/LVV-T3034_M2_analysis_CL_breakout_test-single-window.ipynb new file mode 100644 index 0000000..786eb86 --- /dev/null +++ b/M2_analysis_notebooks/LVV-T3034_M2_analysis_CL_breakout_test-single-window.ipynb @@ -0,0 +1,934 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# M2 forces vs. M2 Closed-loop breakout test" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Readme\n", + "\n", + "This notebook analyzes the evolutions of the measured forces for the tangent and axial actuators during a break-out of the M2 closed-loop during the ramp-up of the TMA slewing speed test campaing. \n", + "Modify the EFD time windows to run again the script on different datasets.\n", + "\n", + "Enter manually the timestamp of the testing window. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import Modules\n", + "\n", + "This notebook needs to setup the **ts_m2com** and **ts_aos_utilsts** under the **notebooks/.user_setups**, which depends on the **ts_tcpip**.\n", + "You also need to have **ts_mtm2** under the **WORK/** directory to read the confiugration files to do the analysis." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%matplotlib inline\n", + "%matplotlib widget \n", + "import matplotlib.pyplot as plt\n", + "import math\n", + "from pathlib import Path\n", + "import numpy as np\n", + "from sklearn.linear_model import LinearRegression\n", + "from astropy.time import Time\n", + "import pandas as pd\n", + "import lsst_efd_client\n", + "\n", + "from lsst.ts.m2com.mock import MockModel\n", + "from lsst.ts.m2com import MockControlClosedLoop\n", + "import tabulate \n", + "from lsst.ts.aos.utils import DiagnosticsM2, EfdName" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## TMA slewing intervals" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# M2 CL break-out intervals - TMA Slewing intervals\n", + "\n", + "slew_intervals = {\n", + " 0: [\n", + " # 1% el 1% az\n", + " Time(\"2024-11-06T08:42:00\",scale=\"utc\", format=\"isot\"),\n", + " Time(\"2024-11-06T08:45:18\",scale=\"utc\", format=\"isot\"),\n", + " ],\n", + "}\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Set title plots" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# create title slewing speed\n", + "title = \"TMA (1%,1%) max speed, M2 with glass\"\n", + "location =\"best\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Functions declaration" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "async def query_data(\n", + " diagnostics_m2: DiagnosticsM2,\n", + " control_closed_loop: MockControlClosedLoop,\n", + " time_start: Time,\n", + " time_end: Time,\n", + ") -> None:\n", + " \"\"\"\n", + " Query the data.\n", + "\n", + " # functions declaration can be found here:\n", + " # https://github.com/lsst-ts/ts_aos_utils/blob/feature/m2power/python/lsst/ts/aos/utils/diagnostics_m2.py\n", + " Parameters\n", + " ----------\n", + " diagnostics_m2 : `lsst.ts.aos.utils.DiagnosticsM2`\n", + " M2 diagnostics instance.\n", + " control_closed_loop : `lsst.ts.m2.com.MockControlClosedLoop`\n", + " Mock control closed loop instance.\n", + " time_start : `astropy.time.core.Time`\n", + " Start time.\n", + " time_end : `astropy.time.core.Time`\n", + " End time.\n", + " \"\"\"\n", + "\n", + " # Get the x, y position of actuators\n", + " xy_actuators = diagnostics_m2.get_xy_actuators(control_closed_loop)\n", + "\n", + " # Query data\n", + " data_ims, time_operation_ims = await diagnostics_m2.get_data_position(\n", + " \"positionIMS\", time_start, time_end\n", + " )\n", + "\n", + " data_collected_axial, data_collected_tangent = await diagnostics_m2.get_data_force(\n", + " time_start, time_end\n", + " )\n", + "\n", + " data_power_status, time_operation = await diagnostics_m2.get_data_power_status(\n", + " time_start, time_end\n", + " )\n", + "\n", + " data_inclinometer = await diagnostics_m2.get_data_zenith_angle(\n", + " time_start, time_end\n", + " )\n", + "\n", + " data_tangent_force_error = await diagnostics_m2.get_data_force_error_tangent(\n", + " time_start, time_end\n", + " )\n", + "\n", + " data_net_moment = await diagnostics_m2.get_data_net_moment(\n", + " time_start, time_end\n", + " )\n", + "\n", + " return xy_actuators, data_ims, data_collected_axial, data_collected_tangent, data_power_status, data_inclinometer, data_net_moment" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def actuator_plot(\n", + " diagnostics_m2,\n", + " control_closed_loop,\n", + " actuators_groups,\n", + " group,\n", + " data_collected_tangent,\n", + " full_stream,\n", + " face,\n", + " data_ims,\n", + " merged_vectors,\n", + " data_inclinometer,\n", + " key,\n", + " m2_cl_status_breakout,\n", + " title,\n", + "):\n", + "\n", + " \n", + "\n", + " \n", + " \n", + " #************************************\n", + " #\n", + " # Set UTC x axis metrics\n", + " #\n", + " #************************************\n", + "\n", + "\n", + " # time stamp closed-loop breakout event\n", + " \n", + " t1 = m2_cl_status_breakout.index[0]\n", + " print(t1)\n", + "\n", + " td = pd.Timedelta(\"0.05 sec\")\n", + "\n", + " cl = np.where(abs(t1 - merged_vectors.index) < td)\n", + "\n", + " t2 = merged_vectors.index[cl]\n", + "\n", + " time_ol_event = t2[0]\n", + " \n", + " print(time_ol_event)\n", + "\n", + " \n", + " time_ol_event = m2_cl_status_breakout.index[0]\n", + " asse = merged_vectors[\"measured0\"]\n", + "\n", + " xx1 = [asse.index[0],time_ol_event, asse.index[-1]]\n", + " xx2 = [asse.index[0], time_ol_event]\n", + " \n", + " tempo = xx1\n", + " tempo2 = xx2\n", + " \n", + " tempo = pd.to_datetime(tempo, format='%Y-%m-%d %H:%M:%S.%f').strftime('%Y-%m-%d %H:%M')\n", + " tempo2 = pd.to_datetime(tempo2, format='%Y-%m-%d %H:%M:%S.%f').strftime('%H:%M:%S')\n", + "\n", + " cl1 = pd.to_datetime(time_ol_event, format='%Y-%m-%d %H:%M:%S.%f').strftime('%Y-%m-%d %H:%M')\n", + " cl2 = pd.to_datetime(time_ol_event, format='%Y-%m-%d %H:%M:%S.%f').strftime('%H:%M:%S')\n", + "\n", + "\n", + " newx2 = [tempo2[0],cl2]\n", + " newx1 = [tempo[0],cl1,tempo[-1]]\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + " #************************************\n", + " #\n", + " # PLOT measured tangent forces\n", + " #\n", + " #************************************\n", + "\n", + " font = {\n", + " \"family\": \"serif\",\n", + " \"color\": \"black\",\n", + " \"weight\": \"normal\",\n", + " \"size\": 10,\n", + " }\n", + "\n", + " hatF = \"$\\overline{F}), N$\"\n", + "\n", + " \n", + " fig = plt.figure()\n", + " fig.subplots_adjust(hspace=0.9, wspace=0.9)\n", + " \n", + " n = 6\n", + " fig.suptitle(title)\n", + "\n", + " for idx in range(n):\n", + " ax = fig.add_subplot(3, 2, idx + 1)\n", + " ax.plot(merged_vectors[f\"measured{idx}\"],color=\"black\")\n", + " ax.set_xticks(xx2, newx2)\n", + " ax.axhline(4893, color=\"orange\", label=\"+CL Max F\")\n", + " ax.axhline(6227, color=\"red\", label=\"+OL Max F\")\n", + " ax.axhline(-4893, color=\"orange\")\n", + " ax.axhline(-6227, color=\"red\")\n", + " ax.axvline(time_ol_event, label = 'CL breakout', color=\"black\", linewidth = \"0.5\")\n", + "\n", + " num_act = actuators_groups[idx] + 1\n", + " ax.set_title(\"A%i\" % (idx + 1), fontdict=font)\n", + " ax.set_ylabel(\"Meas. F, N\", fontdict=font)\n", + "\n", + "\n", + " if idx == 1:\n", + " ax.set_ylim([-7000, 7000])\n", + " ax.legend(loc=\"upper right\", fontsize=\"8\")\n", + " \n", + " elif idx == 2:\n", + " ax.set_ylim([-7000, 7000])\n", + "\n", + " elif idx == 4:\n", + " ax.set_ylim([-7000, 7000])\n", + " ax.set_xlabel(\"UTC\", fontdict=font)\n", + "\n", + " elif idx == 5:\n", + " ax.set_ylim([-7000, 7000])\n", + " ax.set_xlabel(\"UTC\", fontdict=font)\n", + "\n", + "\n", + " \n", + " # ********************************************\n", + " #\n", + " # ISM RBM\n", + " #\n", + " # ********************************************\n", + "\n", + "\n", + "\n", + " font = {\n", + " \"family\": \"serif\",\n", + " \"color\": \"black\",\n", + " \"weight\": \"normal\",\n", + " \"size\": 9,\n", + " }\n", + "\n", + " fig = plt.figure(figsize=(10,8))\n", + "\n", + " ax1 = plt.subplot(231)\n", + " ax1.plot(merged_vectors[\"x\"])\n", + " ax1.set_ylabel(\"IMS x, \\u03BCm\", fontdict=font)\n", + " ax1.axvline(time_ol_event, label = 'CL breakout', color=\"black\", linewidth = \"0.5\")\n", + " ax1.set_xticks(xx2, newx2)\n", + " ax1.legend(loc=\"best\", fontsize=\"8\")\n", + " \n", + " ax2 = plt.subplot(232)\n", + " ax2.plot(merged_vectors[\"y\"])\n", + " ax2.set_ylabel(\"IMS y, \\u03BCm\", fontdict=font)\n", + " ax2.axvline(time_ol_event, color=\"black\", linewidth = \"0.5\")\n", + " ax2.set_xticks(xx2, newx2)\n", + "\n", + " ax3 = plt.subplot(233)\n", + " ax3.plot(merged_vectors[\"z\"])\n", + " ax3.set_ylabel(\"IMS z, \\u03BCm\", fontdict=font)\n", + " ax3.axvline(time_ol_event, color=\"black\", linewidth = \"0.5\")\n", + " ax3.set_xticks(xx2, newx2)\n", + "\n", + " ax4 = plt.subplot(234)\n", + " ax4.plot(merged_vectors[\"xRot\"])\n", + " ax4.set_ylabel(\"IMS xRot, arcsec\", fontdict=font)\n", + " ax4.set_xlabel(\"UTC\", fontdict=font)\n", + " ax4.axvline(time_ol_event, color=\"black\", linewidth = \"0.5\")\n", + " ax4.set_xticks(xx2, newx2)\n", + " \n", + " ax5 = plt.subplot(235)\n", + " ax5.plot(merged_vectors[\"yRot\"])\n", + " ax5.set_ylabel(\"IMS yRot, arcsec\", fontdict=font)\n", + " ax5.set_xlabel(\"UTC\", fontdict=font)\n", + " ax5.axvline(time_ol_event, color=\"black\", linewidth = \"0.5\")\n", + " ax5.set_xticks(xx2, newx2)\n", + " \n", + " \n", + " ax6 = plt.subplot(236)\n", + " ax6.plot(merged_vectors[\"zRot\"])\n", + " ax6.set_ylabel(\"IMS zRot, arcsec\", fontdict=font)\n", + " ax6.set_xlabel(\"UTC\", fontdict=font)\n", + " ax6.axvline(time_ol_event, color=\"black\", linewidth = \"0.5\")\n", + " ax6.set_xticks(xx2, newx2)\n", + " \n", + " fig.suptitle(title)\n", + "\n", + " fig.tight_layout()\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + " # ********************************************\n", + " #\n", + " # Sum & Weight force errors \n", + " #\n", + " # ********************************************\n", + "\n", + "\n", + " font = {\n", + " \"family\": \"serif\",\n", + " \"color\": \"black\",\n", + " \"weight\": \"normal\",\n", + " \"size\": 10,\n", + " }\n", + "\n", + "\n", + " fig = plt.figure()\n", + "\n", + " ax1 = plt.subplot(111)\n", + " fig.suptitle(title)\n", + " ax1.plot(merged_vectors[\"force0\"],label=\"A1 $F_{error}$\")\n", + " ax1.plot(merged_vectors[\"force1\"],label=\"A2 $F_{error}$\")\n", + " ax1.plot(merged_vectors[\"force2\"],label=\"A3 $F_{error}$\")\n", + " ax1.plot(merged_vectors[\"force3\"],label=\"A4 $F_{error}$\")\n", + " ax1.plot(merged_vectors[\"force4\"],label=\"A5 $F_{error}$\")\n", + " ax1.plot(merged_vectors[\"force5\"],label=\"A6 $F_{error}$\")\n", + " ax1.plot(merged_vectors[\"sum\"],label=\"Sum $F_{error} < 1000N$\")\n", + " ax1.plot(merged_vectors[\"weight\"],label=\"Weight $F_{error}$\")\n", + "\n", + " ax1.axvline(time_ol_event, label = 'CL breakout', color=\"black\", linewidth = \"0.5\")\n", + " \n", + " ax1.axhline(1000, linestyle = \"dashed\", color=\"red\")\n", + " ax1.axhline(-1000, linestyle = \"dashed\", color=\"red\")\n", + " ax1.axhline(2000, color=\"red\")\n", + " ax1.axhline(-2000, color=\"red\")\n", + " ax1.set_xticks(xx1,newx1)\n", + " ax1.set_ylabel(\"Tangent force errors, N\", fontdict=font)\n", + " ax1.set_xlabel(\"UTC\", fontdict=font)\n", + " ax1.legend(loc=\"lower right\", fontsize=\"8\")\n", + " ax1.set_title(\"TMA\", fontdict=font)\n", + " \n", + " \n", + " fig.tight_layout()\n", + "\n", + " \n", + "\n", + "\n", + " font = {\n", + " \"family\": \"serif\",\n", + " \"color\": \"black\",\n", + " \"weight\": \"normal\",\n", + " \"size\": 10,\n", + " }\n", + "\n", + " fig = plt.figure()\n", + "\n", + " fig.suptitle(title)\n", + " ax1 = plt.subplot(111)\n", + " lns1 = ax1.plot(merged_vectors[\"inclinometerProcessed\"],label=\"Elevation\", color = \"black\")\n", + " ax1.set_ylabel(\"TMA Elevation, deg\", fontdict=font)\n", + " ax2 = ax1.twinx()\n", + " lns3 = ax1.axvline(time_ol_event, label = 'CL breakout', color=\"black\", linewidth = \"0.5\")\n", + " lns2 = ax2.plot(merged_vectors[\"actualPosition\"],label=\"Azimuth\", color = \"green\");\n", + " ax2.set_ylabel(\"TMA Azimuth, deg\", fontdict=font)\n", + " lns = lns1+lns2+[lns3]\n", + " labs = [l.get_label() for l in lns]\n", + " ax1.legend(lns, labs, loc = \"center right\")\n", + " ax1.set_xticks(xx1,newx1)\n", + " ax1.set_xlabel(\"UTC\", fontdict=font)\n", + " fig.tight_layout()\n", + "\n", + " " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def actuator_plot_axial(\n", + " diagnostics_m2,\n", + " control_closed_loop,\n", + " actuators_groups,\n", + " group,\n", + " data_collected_axial,\n", + " full_stream,\n", + " face,\n", + " data_ims,\n", + " merged_vectors,\n", + " data_inclinometer,\n", + " key,\n", + " m2_cl_status_breakout,\n", + " title,\n", + "):\n", + "\n", + "\n", + " #************************************\n", + " #\n", + " # Set UTC x axis metrics\n", + " #\n", + " #************************************\n", + "\n", + " # time stamp closed-loop breakout event\n", + " \n", + " t1 = m2_cl_status_breakout.index[0]\n", + " print(t1)\n", + "\n", + " td = pd.Timedelta(\"0.05 sec\")\n", + "\n", + " cl = np.where(abs(t1 - merged_vectors.index) < td)\n", + "\n", + " t2 = merged_vectors.index[cl]\n", + "\n", + " time_ol_event = t2[0]\n", + " \n", + " print(time_ol_event)\n", + "\n", + " \n", + " time_ol_event = m2_cl_status_breakout.index[0]\n", + " asse = merged_vectors[\"measured0\"]\n", + "\n", + " xx1 = [asse.index[0],time_ol_event, asse.index[-1]]\n", + " xx2 = [asse.index[0], time_ol_event]\n", + " \n", + " tempo = xx1\n", + " tempo2 = xx2\n", + " \n", + " tempo = pd.to_datetime(tempo, format='%Y-%m-%d %H:%M:%S.%f').strftime('%Y-%m-%d %H:%M')\n", + " tempo2 = pd.to_datetime(tempo2, format='%Y-%m-%d %H:%M:%S.%f').strftime('%H:%M:%S')\n", + "\n", + " cl1 = pd.to_datetime(time_ol_event, format='%Y-%m-%d %H:%M:%S.%f').strftime('%Y-%m-%d %H:%M')\n", + " cl2 = pd.to_datetime(time_ol_event, format='%Y-%m-%d %H:%M:%S.%f').strftime('%H:%M:%S')\n", + "\n", + "\n", + " newx2 = [tempo2[0],cl2]\n", + " newx1 = [tempo[0],cl1,tempo[-1]]\n", + "\n", + "\n", + " \n", + "\n", + " #************************************\n", + " #\n", + " # PLOT measured axial forces\n", + " #\n", + " #************************************\n", + "\n", + " font = {\n", + " \"family\": \"serif\",\n", + " \"color\": \"black\",\n", + " \"weight\": \"normal\",\n", + " \"size\": 10,\n", + " }\n", + "\n", + " hatF = \"$\\overline{F}), N$\"\n", + " \n", + " fig = plt.figure()\n", + " \n", + " n = 72\n", + " fig.suptitle(title)\n", + " ax = fig.add_subplot(1, 1, 1)\n", + " \n", + " for idx in range(n):\n", + " ax.plot(merged_vectors[f\"measured{idx}\"])\n", + " ax.set_xticks(xx1,newx1)\n", + " ax.axhline(444, color=\"orange\", label=\"+CL Max F\")\n", + " ax.axhline(666, color=\"red\", label=\"+OL Max F\")\n", + " ax.axhline(-444, color=\"orange\")\n", + " ax.axhline(-666, color=\"red\") \n", + " ax.axvline(time_ol_event, label = 'CL breakout', color=\"black\", linewidth = \"0.5\")\n", + " ax.set_ylabel(\"Measured axial forces, N\", fontdict=font)\n", + " ax.set_xlabel(\"UTC\", fontdict=font)\n", + " ax.legend(loc=\"upper right\", fontsize=\"8\")\n", + "\n", + " " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def add_force_error(data: pd.DataFrame) -> pd.DataFrame:\n", + " \n", + "\n", + " df = data.copy()\n", + " cols = [\"force0\", \"force1\", \"force2\", \"force3\", \"force4\", \"force5\", \"weight\", \"sum\"]\n", + "\n", + "\n", + " for i, row in enumerate(data.iterrows()):\n", + " if abs(row[1][\"inclinometerRaw\"]) > 360:\n", + " c = 1\n", + " searching = True\n", + " while searching:\n", + " eval_angle = data.loc[data.index[i - c], \"inclinometerRaw\"]\n", + " if abs(eval_angle) < 360:\n", + " angle = eval_angle\n", + " searching = False\n", + " else:\n", + " c += 1\n", + " else:\n", + " angle = row[1][\"inclinometerRaw\"]\n", + "\n", + " mock = MockModel()\n", + " angle = mock.control_open_loop.correct_inclinometer_angle(angle)\n", + " mock.control_open_loop.inclinometer_angle = angle\n", + "\n", + " tangent_force_error = mock._calculate_force_error_tangent(\n", + " np.array(\n", + " [\n", + " row[1][\"measured0\"],\n", + " row[1][\"measured1\"],\n", + " row[1][\"measured2\"],\n", + " row[1][\"measured3\"],\n", + " row[1][\"measured4\"],\n", + " row[1][\"measured5\"],\n", + " ]\n", + " )\n", + " )\n", + "\n", + " df.loc[row[0], cols[:-2]] = tangent_force_error[\"force\"]\n", + " df.loc[row[0], cols[-2]] = tangent_force_error[\"weight\"]\n", + " df.loc[row[0], cols[-1]] = tangent_force_error[\"sum\"]\n", + "\n", + " return df" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "async def get_merge_query(\n", + " efd_client: lsst_efd_client.EfdClient,\n", + " topics: list,\n", + " start_time: Time,\n", + " end_time: Time,\n", + " tolerance=None,\n", + " direction: str = None,\n", + "):\n", + " query_df = list()\n", + " calculate_force_error = False\n", + " for topic in topics:\n", + " topic_fields = await efd_client.get_fields(topic)\n", + " query = efd_client.build_time_range_query(\n", + " topic, topic_fields, start_time, end_time\n", + " )\n", + " data_query = await efd_client.influx_client.query(query)\n", + " if len(data_query) == 0 and topic == \"lsst.sal.MTM2.forceErrorTangent\":\n", + " print(f\"{topic} is not present, try to calculate it.\")\n", + " calculate_force_error = True\n", + " elif len(data_query) == 0:\n", + " print(f\"{topic} is not present.\")\n", + " else:\n", + " query_df.append(data_query)\n", + " if len(query_df) == 1:\n", + " return query_df[0]\n", + " elif len(query_df) == 0:\n", + " print(\"No Dataframe retrieve\")\n", + " return query_df\n", + " query_df.sort(key=lambda el: len(el), reverse=True)\n", + " merge_df = query_df[0].copy()\n", + " for i, df in enumerate(query_df[1:]):\n", + " col_left = topics[i].split(\".\")[-1]\n", + " col_right = topics[i + 1].split(\".\")[-1]\n", + " if tolerance is None and direction is None:\n", + " merge_df = lsst_efd_client.rendezvous_dataframes(\n", + " merge_df,\n", + " df,\n", + " direction=\"nearest\",\n", + " suffixes=[f\"_{col_left}\", f\"_{col_right}\"],\n", + " )\n", + " elif tolerance is None and direction is not None:\n", + " merge_df = lsst_efd_client.rendezvous_dataframes(\n", + " merge_df,\n", + " df,\n", + " direction=direction,\n", + " suffixes=[f\"_{col_left}\", f\"_{col_right}\"],\n", + " )\n", + " elif tolerance is not None and direction is None:\n", + " merge_df = lsst_efd_client.rendezvous_dataframes(\n", + " merge_df,\n", + " df,\n", + " direction=\"nearest\",\n", + " tolerance=tolerance,\n", + " suffixes=[f\"_{col_left}\", f\"_{col_right}\"],\n", + " )\n", + " else:\n", + " merge_df = lsst_efd_client.rendezvous_dataframes(\n", + " merge_df,\n", + " df,\n", + " direction=direction,\n", + " tolerance=tolerance,\n", + " suffixes=[f\"_{col_left}\", f\"_{col_right}\"],\n", + " )\n", + " if calculate_force_error:\n", + " merge_df = add_force_error(merge_df)\n", + " return merge_df\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def spot_cl_breakout_event(\n", + " merged_vectors,\n", + " key,\n", + "):\n", + " \n", + " \n", + " # find M2 closed loop break-out time\n", + "\n", + " \n", + " useful_index = []\n", + " \n", + " \n", + " # find M2 closed loop break-out time \n", + " #if m2_cl_status.shape[0] == 0:\n", + " # continue\n", + "\n", + " for i, status in enumerate(m2_cl_status[\"mode\"]):\n", + " print(status)\n", + " # find open loop event = 3\n", + " if (status == 3):\n", + " useful_index.append(i)\n", + "\n", + " if len(useful_index) != 0:\n", + " print(\"Timestamp M2 CL breakout:\")\n", + " print(useful_index[0], m2_cl_status.index[useful_index[0]])\n", + "\n", + " m2_cl_status_breakout = m2_cl_status.index[useful_index[0]]\n", + " \n", + " return useful_index, m2_cl_status_breakout" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Instantiate the MockControlClosedLoop" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "config_path = Path.home() / \"WORK\" / \"ts_mtm2\" / \"config\" / \"parameter_files\"\n", + "filepath_cell_geom = Path.home() / \"WORK\" / \"ts_mtm2\" / \"config\" / \"cellGeom.json\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "control_closed_loop = MockControlClosedLoop()\n", + "control_closed_loop.load_file_cell_geometry(filepath_cell_geom)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Instantiate the DiagnosticsM2 Class\n", + "\n", + "Notice that the UTC time is used when doing the query." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "diagnostics_m2 = DiagnosticsM2(efd_name=EfdName.Usdf)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Instatiate EFD client" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "efd_client = lsst_efd_client.EfdClient(efd_name=\"usdf_efd\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Tangent actuators" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "actuators_groups = np.array([72, 73, 74, 75, 76, 77])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "\n", + "# Plots for tangent actuators\n", + "\n", + "for key, val in slew_intervals.items():\n", + " time_start = val[0]\n", + " time_end = val[1]\n", + "\n", + "\n", + " (\n", + " xy_actuators,\n", + " data_ims, \n", + " data_collected_axial, \n", + " data_collected_tangent, \n", + " data_power_status, \n", + " data_inclinometer,\n", + " data_net_moment,\n", + " ) = await query_data(diagnostics_m2, control_closed_loop, time_start, time_end)\n", + "\n", + " \n", + "\n", + " merged_vectors = await get_merge_query(\n", + " efd_client,\n", + " [\n", + " \"lsst.sal.MTM2.tangentEncoderPositions\", \n", + " \"lsst.sal.MTM2.tangentForce\",\n", + " \"lsst.sal.MTM2.forceErrorTangent\",\n", + " \"lsst.sal.MTM2.positionIMS\",\n", + " \"lsst.sal.MTM2.displacementSensors\",\n", + " \"lsst.sal.MTM2.zenithAngle\",\n", + " \"lsst.sal.MTM2.forceBalance\",\n", + " \"lsst.sal.MTMount.azimuth\",\n", + " ],\n", + " time_start,\n", + " time_end,\n", + " \n", + " )\n", + "\n", + " \n", + " m2_cl_status_breakout = await efd_client.select_time_series(\n", + " \"lsst.sal.MTM2.logevent_closedLoopControlMode\",\n", + " fields=[\"mode\"],\n", + " start=time_start,\n", + " end=time_end) \n", + "\n", + "\n", + "\n", + " full_stream = len(data_collected_tangent[\"measured\"])\n", + " \n", + " actuator_plot(\n", + " diagnostics_m2,\n", + " control_closed_loop,\n", + " actuators_groups,\n", + " key,\n", + " data_collected_tangent,\n", + " full_stream,\n", + " \"down\",\n", + " data_ims,\n", + " merged_vectors,\n", + " data_inclinometer,\n", + " key,\n", + " m2_cl_status_breakout,\n", + " title,\n", + " )\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "\n", + "# Plots for axial actuators\n", + "\n", + "for key, val in slew_intervals.items():\n", + " time_start = val[0]\n", + " time_end = val[1]\n", + "\n", + "\n", + " (\n", + " xy_actuators,\n", + " data_ims, \n", + " data_collected_axial, \n", + " data_collected_tangent, \n", + " data_power_status, \n", + " data_inclinometer,\n", + " data_net_moment,\n", + " ) = await query_data(diagnostics_m2, control_closed_loop, time_start, time_end)\n", + "\n", + " \n", + "\n", + " merged_vectors = await get_merge_query(\n", + " efd_client,\n", + " [\n", + " \"lsst.sal.MTM2.axialEncoderPositions\", \n", + " \"lsst.sal.MTM2.axialForce\",\n", + " \"lsst.sal.MTM2.forceErrorTangent\",\n", + " \"lsst.sal.MTM2.zenithAngle\",\n", + " \"lsst.sal.MTM2.forceBalance\",\n", + " \"lsst.sal.MTMount.azimuth\",\n", + " ],\n", + " time_start,\n", + " time_end,\n", + " \n", + " )\n", + "\n", + " full_stream = len(data_collected_axial[\"measured\"])\n", + " \n", + " actuator_plot_axial(\n", + " diagnostics_m2,\n", + " control_closed_loop,\n", + " actuators_groups,\n", + " key,\n", + " data_collected_axial,\n", + " full_stream,\n", + " \"down\",\n", + " data_ims,\n", + " merged_vectors,\n", + " data_inclinometer,\n", + " key,\n", + " m2_cl_status_breakout,\n", + " title,\n", + " )\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "LSST", + "language": "python", + "name": "lsst" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.9" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +}