Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion src/data/accel/hbk/aligner.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,6 @@ def extract(self, requested_samples: int) -> Tuple[np.ndarray, Optional[datetime
with self._lock:
batch_size, key_groups = self.find_continuous_key_groups()
#print("Keys", key_groups)

if batch_size is None or key_groups is None:
# No data or groups to align, returun empty
return np.empty((0, len(self.channels)), dtype=np.float32), None
Expand Down
11 changes: 11 additions & 0 deletions src/data/comm/mqtt.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,3 +121,14 @@ def setup_mqtt_client(config, topic_index=0):
mqttc.on_publish = create_on_publish_callback()

return mqttc, selected_topic

def reconnect_client(mqtt_client) -> bool:
if not mqtt_client.is_connected():
print("Client disconnected. Reconnecting...")
mqtt_client.reconnect()

if not mqtt_client.is_connected():
raise Exception("Clint is not connected")
else:
print("Succesfully connected")
return True
19 changes: 11 additions & 8 deletions src/examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,11 +74,15 @@ python .\src\examples\example.py live-sysid-publish
python .\src\examples\example.py clustering-with-local-sysid
python .\src\examples\example.py clustering-with-remote-sysid
python .\src\examples\example.py live-clustering-with-remote-sysid
python .\src\examples\example.py mode-tracking-with-remote-sysid
python .\src\examples\example.py live-clustering-with-remote-sysid-and-publish
python .\src\examples\example.py mode-tracking-with-local-sysid
python .\src\examples\example.py live-mode-tracking-remote-sysid
python .\src\examples\example.py mode-tracking-with-remote-sysid
python .\src\examples\example.py live-mode-tracking-with-remote-sysid
python .\src\examples\example.py model-update-local-sysid
python .\src\examples\example.py live-model-update-remote-sysid
python .\src\examples\example.py live-model-update-remote-clustering
python .\src\examples\example.py live-model-update-remote-clustering-and-publish

```

To run the examples with specified config, use
Expand Down Expand Up @@ -116,21 +120,20 @@ poetry run python src/scripts/publish_samples.py

## Machine 2: Fog Layer – Data Alignment and System Identification

This machine subscribes to MQTT topics from Machine 1. It aligns multi-channel data, runs system identification,
and publishes pyOMA results.
This machine subscribes to MQTT topics from Machine 1. It aligns multi-channel data, runs system identification, and continuously publishes SysID results.

Run the aligner and system identification pipeline

```bash
poetry run python src/examples/example.py oma-and-publish
poetry run python src/examples/example.py live-sysid-publish
```

## Machine 3: Cloud Layer – Mode Tracking and Model Update

This machine subscribes to pyOMA results, performs mode tracking and updates the structural model.
This machine subscribes to SysID results, and performs mode tracking.

Run mode tracking and model update
Run mode tracking

```bash
poetry run python src/examples/example.py model-update-remote-sysid
poetry run python src/examples/example.py mode-tracking-with-remote-sysid
```
2 changes: 1 addition & 1 deletion src/examples/aligning_readings.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
def align_acceleration_readings(config_path):
config = load_config(config_path)
mqtt_config = config["MQTT"]
topic_indexes = [0,2]
topic_indexes = [0, 2, 3, 4]

all_topics = mqtt_config["TopicsToSubscribe"]
selected_topics = [all_topics[i] for i in topic_indexes]
Expand Down
40 changes: 29 additions & 11 deletions src/examples/example.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
from examples.run_mode_clustering import (
run_mode_clustering_with_local_sysid,
run_mode_clustering_with_remote_sysid,
run_live_mode_clustering_with_remote_sysid
run_live_mode_clustering_with_remote_sysid,
run_live_mode_clustering_with_remote_sysid_and_publish
)
from examples.run_mode_tracking import (
run_mode_tracking_with_local_sysid,
Expand All @@ -20,10 +21,11 @@
)
from examples.run_model_update import (
run_model_update_local_sysid,
run_model_update_remote_sysid
run_model_update_remote_sysid,
run_live_model_update_remote_clustering,
run_live_model_update_with_remote_clustering_and_publish,
)


@click.group()
@click.option('--config', default="config/production.json", help="Path to config file")
@click.pass_context
Expand All @@ -43,23 +45,23 @@ def align_readings(ctx):

@cli.command()
@click.pass_context
def sysid_and_publish(ctx):
run_sysid_and_publish(ctx.obj["CONFIG"])
def sysid_and_print(ctx):
run_sysid_and_print(ctx.obj["CONFIG"])

@cli.command()
@click.pass_context
def live_sysid_publish(ctx):
live_sysid_and_publish(ctx.obj["CONFIG"])
def sysid_and_plot(ctx):
run_sysid_and_plot(ctx.obj["CONFIG"])

@cli.command()
@click.pass_context
def sysid_and_plot(ctx):
run_sysid_and_plot(ctx.obj["CONFIG"])
def sysid_and_publish(ctx):
run_sysid_and_publish(ctx.obj["CONFIG"])

@cli.command()
@click.pass_context
def sysid_and_print(ctx):
run_sysid_and_print(ctx.obj["CONFIG"])
def live_sysid_publish(ctx):
live_sysid_and_publish(ctx.obj["CONFIG"])

@cli.command()
@click.pass_context
Expand All @@ -76,6 +78,11 @@ def clustering_with_remote_sysid(ctx):
def live_clustering_with_remote_sysid(ctx):
run_live_mode_clustering_with_remote_sysid(ctx.obj["CONFIG"])

@cli.command()
@click.pass_context
def live_clustering_with_remote_sysid_and_publish(ctx):
run_live_mode_clustering_with_remote_sysid_and_publish(ctx.obj["CONFIG"])

@cli.command()
@click.pass_context
def mode_tracking_with_local_sysid(ctx):
Expand All @@ -101,5 +108,16 @@ def model_update_local_sysid(ctx):
def live_model_update_remote_sysid(ctx):
run_model_update_remote_sysid(ctx.obj["CONFIG"])

@cli.command()
@click.pass_context
def live_model_update_remote_clustering(ctx):
run_live_model_update_remote_clustering(ctx.obj["CONFIG"])

@cli.command()
@click.pass_context
def live_model_update_remote_clustering_and_publish(ctx):
run_live_model_update_with_remote_clustering_and_publish(ctx.obj["CONFIG"])


if __name__ == "__main__":
cli(obj={})
13 changes: 8 additions & 5 deletions src/examples/run_mode_clustering.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,9 @@ def run_mode_clustering_with_local_sysid(config_path):
sysid_output, aligner_time = sysID.get_sysid_results(number_of_minutes, aligner, fs)
data_client.disconnect()

# Mode Tracks
# Mode clustering
dictionary_of_clusters, median_frequencies = MC.cluster_sysid(
sysid_output,PARAMS)

# Print frequencies
print("\nMedian frequencies:", median_frequencies)

Expand All @@ -44,10 +43,14 @@ def run_mode_clustering_with_local_sysid(config_path):
sys.stdout.flush()

def run_mode_clustering_with_remote_sysid(config_path):
sysid_output, dictionary_of_clusters, meadian_frequencies = MC.subscribe_and_cluster(config_path,PARAMS)
fig_ax = plot_clusters(dictionary_of_clusters, sysid_output, PARAMS, fig_ax = None)
plt.show(block=True)
cluster_results, sysid_output, dictionary_of_clusters, meadian_frequencies, timestamp = MC.subscribe_and_cluster(config_path,PARAMS)
if sysid_output is not None:
fig_ax = plot_clusters(dictionary_of_clusters, sysid_output, PARAMS, fig_ax = None)
plt.show(block=True)
sys.stdout.flush()

def run_live_mode_clustering_with_remote_sysid(config_path):
MC.live_mode_clustering(config_path,topic_index=0,plot=[1,1])

def run_live_mode_clustering_with_remote_sysid_and_publish(config_path):
MC.live_mode_clustering_publish(config_path,topic_index=0)
5 changes: 3 additions & 2 deletions src/examples/run_mode_tracking.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,9 @@ def run_mode_tracking_with_local_sysid(config_path):

def run_mode_tracking_with_remote_sysid(config_path):
sysid_output, clusters, tracked_clusters = MT.subscribe_and_track_clusters(config_path)
fig_ax = plot_tracked_modes(tracked_clusters, PARAMS, fig_ax = None, x_length = None)
plt.show(block=True)
if sysid_output is not None:
fig_ax = plot_tracked_modes(tracked_clusters, PARAMS, fig_ax = None, x_length = None)
plt.show(block=True)
sys.stdout.flush()

def run_live_mode_tracking_with_remote_sysid(config_path):
Expand Down
74 changes: 15 additions & 59 deletions src/examples/run_model_update.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,20 @@
from data.accel.hbk.aligner import Aligner
from methods import sysid as sysID
from methods import mode_clustering as MC
from methods import model_update as MU
from methods.constants import PARAMS
from methods import model_update
from methods.constants import PARAMS, MODEL_PARAMETERS
# pylint: disable=R0914, C0103

def run_model_update_local_sysid(config_path):
number_of_minutes = 5
number_of_minutes = 1
config = load_config(config_path)
mqtt_config = config["MQTT"]

# Setting up the client and extracting Fs
data_client, fs = sysID.setup_client(mqtt_config)

# Setting up the aligner
data_topic_indexes = [0, 2]
data_topic_indexes = [0, 2, 3, 4]
selected_topics = [mqtt_config["TopicsToSubscribe"][i] for i in data_topic_indexes]
aligner = Aligner(data_client, topics=selected_topics)

Expand All @@ -27,65 +27,21 @@ def run_model_update_local_sysid(config_path):
oma_output, aligner_time = sysID.get_sysid_results(number_of_minutes, aligner, fs)
data_client.disconnect()

# Mode Track
# Mode clustering
dictionary_clusters, median_frequencies = MC.cluster_sysid(oma_output,PARAMS)

# Run model update
update_result = MU.run_model_update(dictionary_clusters)

if update_result is not None:
optimized_parameters = update_result['optimized_parameters']
omegaN_rad = update_result['omegaN_rad']
omegaN_Hz = update_result['omegaN_Hz']
mode_shapes = update_result['mode_shapes']
damping_matrix = update_result['damping_matrix']
pars_model = update_result['pars_updated']
system_up = update_result['System_updated']

print("\nOptimized parameters (k, m):", optimized_parameters)
print("\nNatural frequencies (rad/s):", omegaN_rad)
print("\nNatural frequencies (Hz):", omegaN_Hz)
print("\nMode shapes (normalized):\n", mode_shapes)
print("\nDamping matrix:\n", damping_matrix)
print("\nUpdated model parameters (dictionary):", pars_model)
print("\nUpdated system:")
print("\nMass matrix M:", system_up["M"])
print("\nStiffness matrix K:\n", system_up["K"])
print("\nDamping matrix C:\n", system_up["C"])

else:
print("Model update failed.")


parameters, omegaMU, model_parameters = model_update.estimate_updated_model(dictionary_clusters,MODEL_PARAMETERS,PARAMS)

def run_model_update_remote_sysid(config_path):
config = load_config(config_path)
sysid_output, clusters, median_frequencies = (
MC.subscribe_and_cluster(config_path)
)

# Run model update
update_result = MU.run_model_update(clusters)
model_update.live_model_update_with_remote_sysid(config_path)

if update_result is not None:
optimized_parameters = update_result['optimized_parameters']
omegaN_rad = update_result['omegaN_rad']
omegaN_Hz = update_result['omegaN_Hz']
mode_shapes = update_result['mode_shapes']
damping_matrix = update_result['damping_matrix']
pars_model = update_result['pars_updated']
system_up = update_result['System_updated']
def run_live_model_update_remote_clustering(config_path):
model_update.live_model_update_with_remote_clustering(config_path)

print("\nOptimized parameters (k, m):", optimized_parameters)
print("\nNatural frequencies (rad/s):", omegaN_rad)
print("\nNatural frequencies (Hz):", omegaN_Hz)
print("\nMode shapes (normalized):\n", mode_shapes)
print("\nDamping matrix:\n", damping_matrix)
print("\nUpdated model parameters (dictionary):", pars_model)
print("\nUpdated system:")
print("\nMass matrix M:", system_up["M"])
print("\nStiffness matrix K:\n", system_up["K"])
print("\nDamping matrix C:\n", system_up["C"])

else:
print("Model update failed.")
def run_live_model_update_with_remote_clustering_and_publish(config_path):
config = load_config(config_path)
publish_config = config["model_update"]
publish_client, publish_topic = MC.setup_publish_client(publish_config)
# publish_topic = publish_config["TopicsToSubscribe"][0]
model_update.live_model_update_with_remote_clustering_and_publish(config_path,publish_client,publish_topic)
10 changes: 5 additions & 5 deletions src/examples/run_sysid.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def setup_sysid(config_path, data_topic_indexes):


def run_sysid_and_plot(config_path):
number_of_minutes = 1
number_of_minutes = 0.2
data_topic_indexes = [0, 2, 3, 4]
aligner, data_client, fs = setup_sysid(config_path, data_topic_indexes)

Expand Down Expand Up @@ -86,7 +86,7 @@ def run_sysid_and_publish(config_path):
# Setting up the client for publishing sysid results
publish_client, _ = sysID.setup_client(publish_config) # fs not needed here

publish_result = sysID.publish_sysid_results(
publish_result, timestamp = sysID.publish_sysid_results(
number_of_minutes,
aligner,
publish_client,
Expand All @@ -95,7 +95,7 @@ def run_sysid_and_publish(config_path):
)

if publish_result is True:
print(f"Publishing to topic: {publish_config['TopicsToSubscribe'][0]}")
print(f"Publishing to topic: {publish_config['TopicsToSubscribe'][0]} at time: {timestamp}")
data_client.disconnect()
sys.stdout.flush()

Expand All @@ -111,12 +111,12 @@ def live_sysid_and_publish(config_path):

publish_result = True
while publish_result:
publish_result = sysID.publish_sysid_results(
publish_result, timestamp = sysID.publish_sysid_results(
number_of_minutes,
aligner,
publish_client,
publish_config["TopicsToSubscribe"][0],
fs
)
if publish_result is True:
print(f"Publishing to topic: {publish_config['TopicsToSubscribe'][0]}")
print(f"Publishing to topic: {publish_config['TopicsToSubscribe'][0]} at time: {timestamp}")
4 changes: 3 additions & 1 deletion src/functions/calculate_mac.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,7 @@ def calculate_mac(reference_mode_shape: np.array, second_mode_shape: np.array) -

"""
numerator = np.abs(np.dot(reference_mode_shape.conj().T, second_mode_shape)) ** 2
denominator = np.dot(reference_mode_shape.conj().T, reference_mode_shape) * np.dot(second_mode_shape.conj().T, second_mode_shape)
denominator = np.dot(reference_mode_shape.conj().T,
reference_mode_shape) * np.dot(second_mode_shape.conj().T,
second_mode_shape)
return np.real(numerator / denominator)
8 changes: 4 additions & 4 deletions src/functions/plot_clusters.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,15 +88,15 @@ def plot_clusters(clusters: Dict[str,dict],
return fig, (ax1,ax2)


def add_scatter_cluster(ax: matplotlib.axes.Axes, x: np.ndarray[float], y: np.ndarray[float], cov: np.ndarray[float], cluster_id = int, error_dir: str = "h") -> Tuple[matplotlib.axes.Axes, Any]:
def add_scatter_cluster(ax: matplotlib.axes.Axes, x: np.ndarray, y: np.ndarray, cov: np.ndarray, cluster_id = int, error_dir: str = "h") -> Tuple[matplotlib.axes.Axes, Any]:
"""
Add scatter plot of clusters to existing axes

Args:
ax (matplotlib.axes.Axes): ax from matplotlib
x (np.ndarray[float]): x-axis data
y (np.ndarray[float]): y-axis data
cov (np.ndarray[float]): covariance for errorbars
x (np.ndarray): x-axis data
y (np.ndarray): y-axis data
cov (np.ndarray): covariance for errorbars
cluster_id (int): Index of cluster for labeling
error_dir (str): Direction of errorbars, either "h" horizontal or "v" vertical

Expand Down
Loading
Loading