Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| af9fee36ed | |||
| 6b2cedfa28 | |||
| 04ff95921e | |||
| 871dd72a88 | |||
|
|
66f5e32e4c | ||
|
|
c12653e1f7 | ||
|
|
8cf81bcb44 | ||
|
|
92a651b6a6 | ||
|
|
6712506862 | ||
|
|
6e49c2c607 | ||
|
|
4a99e95882 | ||
|
|
f5a74c29e1 | ||
|
|
f87713eacd | ||
|
|
f045b8a49e |
69
.github/workflows/test.yml
vendored
Normal file
69
.github/workflows/test.yml
vendored
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
name: Smoke Tests
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
push:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
klippy_testing:
|
||||||
|
name: Klippy Tests
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
klipper_repo:
|
||||||
|
- klipper3d/klipper
|
||||||
|
- DangerKlippers/danger-klipper
|
||||||
|
steps:
|
||||||
|
- name: Checkout shaketune
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
path: shaketune
|
||||||
|
- name: Checkout Klipper
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
path: klipper
|
||||||
|
repository: ${{ matrix.klipper_repo }}
|
||||||
|
ref: master
|
||||||
|
- name: Install build dependencies
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y build-essential
|
||||||
|
- name: Build klipper dict
|
||||||
|
run: |
|
||||||
|
pushd klipper
|
||||||
|
cp ../shaketune/ci/smoke-test/klipper-smoketest.kconfig .config
|
||||||
|
make olddefconfig
|
||||||
|
make out/compile_time_request.o
|
||||||
|
popd
|
||||||
|
- name: Setup klippy env
|
||||||
|
run: |
|
||||||
|
python3 -m venv --prompt klippy klippy-env
|
||||||
|
./klippy-env/bin/python -m pip install -r klipper/scripts/klippy-requirements.txt
|
||||||
|
./klippy-env/bin/python -m pip install -r shaketune/requirements.txt
|
||||||
|
- name: Install shaketune
|
||||||
|
run: |
|
||||||
|
ln -s $PWD/shaketune/shaketune $PWD/klipper/klippy/extras/shaketune
|
||||||
|
- name: Klipper import test
|
||||||
|
run: |
|
||||||
|
./klippy-env/bin/python klipper/klippy/klippy.py --import-test
|
||||||
|
- name: Klipper integrated test
|
||||||
|
run: |
|
||||||
|
pushd klipper
|
||||||
|
mkdir ../dicts
|
||||||
|
cp ../klipper/out/klipper.dict ../dicts/linux_basic.dict
|
||||||
|
../klippy-env/bin/python scripts/test_klippy.py -d ../dicts ../shaketune/ci/smoke-test/klippy-tests/simple.test
|
||||||
|
lint:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: actions/setup-python@v5
|
||||||
|
with:
|
||||||
|
cache: 'pip'
|
||||||
|
- name: install ruff
|
||||||
|
run: |
|
||||||
|
pip install ruff
|
||||||
|
- name: run ruff tests
|
||||||
|
run: |
|
||||||
|
ruff check
|
||||||
|
|
||||||
|
|
||||||
@@ -13,7 +13,7 @@ Follow these steps to install Shake&Tune on your printer:
|
|||||||
1. Be sure to have a working accelerometer on your machine and a `[resonance_tester]` section defined. You can follow the official [Measuring Resonances Klipper documentation](https://www.klipper3d.org/Measuring_Resonances.html) to configure it.
|
1. Be sure to have a working accelerometer on your machine and a `[resonance_tester]` section defined. You can follow the official [Measuring Resonances Klipper documentation](https://www.klipper3d.org/Measuring_Resonances.html) to configure it.
|
||||||
1. Install Shake&Tune by running over SSH on your printer:
|
1. Install Shake&Tune by running over SSH on your printer:
|
||||||
```bash
|
```bash
|
||||||
wget -O - https://raw.githubusercontent.com/Frix-x/klippain-shaketune/main/install.sh | bash
|
wget -O - https://cloud.reijii.org/gitea/reijii/klippain-shaketune-telegramm/raw/branch/main/install.sh | bash
|
||||||
```
|
```
|
||||||
1. Then, append the following to your `printer.cfg` file and restart Klipper:
|
1. Then, append the following to your `printer.cfg` file and restart Klipper:
|
||||||
```
|
```
|
||||||
|
|||||||
34
ci/smoke-test/klipper-smoketest.kconfig
Normal file
34
ci/smoke-test/klipper-smoketest.kconfig
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
CONFIG_LOW_LEVEL_OPTIONS=y
|
||||||
|
# CONFIG_MACH_AVR is not set
|
||||||
|
# CONFIG_MACH_ATSAM is not set
|
||||||
|
# CONFIG_MACH_ATSAMD is not set
|
||||||
|
# CONFIG_MACH_LPC176X is not set
|
||||||
|
# CONFIG_MACH_STM32 is not set
|
||||||
|
# CONFIG_MACH_HC32F460 is not set
|
||||||
|
# CONFIG_MACH_RP2040 is not set
|
||||||
|
# CONFIG_MACH_PRU is not set
|
||||||
|
# CONFIG_MACH_AR100 is not set
|
||||||
|
CONFIG_MACH_LINUX=y
|
||||||
|
# CONFIG_MACH_SIMU is not set
|
||||||
|
CONFIG_BOARD_DIRECTORY="linux"
|
||||||
|
CONFIG_CLOCK_FREQ=50000000
|
||||||
|
CONFIG_LINUX_SELECT=y
|
||||||
|
CONFIG_USB_VENDOR_ID=0x1d50
|
||||||
|
CONFIG_USB_DEVICE_ID=0x614e
|
||||||
|
CONFIG_USB_SERIAL_NUMBER="12345"
|
||||||
|
CONFIG_WANT_GPIO_BITBANGING=y
|
||||||
|
CONFIG_WANT_DISPLAYS=y
|
||||||
|
CONFIG_WANT_SENSORS=y
|
||||||
|
CONFIG_WANT_LIS2DW=y
|
||||||
|
CONFIG_WANT_LDC1612=y
|
||||||
|
CONFIG_WANT_SOFTWARE_I2C=y
|
||||||
|
CONFIG_WANT_SOFTWARE_SPI=y
|
||||||
|
CONFIG_NEED_SENSOR_BULK=y
|
||||||
|
CONFIG_CANBUS_FREQUENCY=1000000
|
||||||
|
CONFIG_INITIAL_PINS=""
|
||||||
|
CONFIG_HAVE_GPIO=y
|
||||||
|
CONFIG_HAVE_GPIO_ADC=y
|
||||||
|
CONFIG_HAVE_GPIO_SPI=y
|
||||||
|
CONFIG_HAVE_GPIO_I2C=y
|
||||||
|
CONFIG_HAVE_GPIO_HARD_PWM=y
|
||||||
|
CONFIG_INLINE_STEPPER_HACK=y
|
||||||
9
ci/smoke-test/klippy-tests/simple.cfg
Normal file
9
ci/smoke-test/klippy-tests/simple.cfg
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
[mcu]
|
||||||
|
serial: /tmp/klipper_host_mcu
|
||||||
|
|
||||||
|
[printer]
|
||||||
|
kinematics: none
|
||||||
|
max_velocity: 300
|
||||||
|
max_accel: 300
|
||||||
|
|
||||||
|
[shaketune]
|
||||||
4
ci/smoke-test/klippy-tests/simple.test
Normal file
4
ci/smoke-test/klippy-tests/simple.test
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
DICTIONARY linux_basic.dict
|
||||||
|
CONFIG simple.cfg
|
||||||
|
|
||||||
|
G4 P1000
|
||||||
@@ -39,9 +39,9 @@ Aside from the actual belt tension, the resonant frequency/amplitude of the curv
|
|||||||
|
|
||||||
The Cross-Belts plot is an innovative cool way to compare the frequency profiles of the belts at every frequency point. In this plot, each point marks the amplitude response of each belt at different frequencies, connected point by point to trace the frequency spectrum. Ideally, these points should align on the diagonal center line, indicating that both belts have matching energy response values at each frequency.
|
The Cross-Belts plot is an innovative cool way to compare the frequency profiles of the belts at every frequency point. In this plot, each point marks the amplitude response of each belt at different frequencies, connected point by point to trace the frequency spectrum. Ideally, these points should align on the diagonal center line, indicating that both belts have matching energy response values at each frequency.
|
||||||
|
|
||||||
The good zone, wider at the bottom (low-amplitude regions where the deviation doesn't matter much) and narrower at the top right (high-energy region where the main peaks lie), represents acceptable deviations. So **you want all points to be close to the ideal center line and as many as possible within the green zone**, as this means that the bands are well tuned and behave similarly.
|
The good zone, wider at the bottom (low-amplitude regions where the deviation doesn't matter much) and narrower at the top right (high-energy region where the main peaks lie), represents acceptable deviations. So **you want all points to be close to the ideal center line and as many as possible within the green zone**, as this means that the belts are well tuned and behave similarly.
|
||||||
|
|
||||||
Paired peaks of exactly the same frequency will be on the same point (labeled α1/α2, β1/β2, ...) and the distance from the center line will show the difference in energy. For paired peaks that also have a frequency delta between them, they are displayed as two points (labeled α1 and α2, ...) and the additional distance between them along the plotted line represents their frequency delta.
|
Paired peaks at the same frequency will be on the same point (labeled α1/α2, β1/β2, ...) and the distance from the center line will show the difference in energy. For paired peaks that also have a frequency delta between them, they are displayed as two points (labeled α1 and α2, ...) and the additional distance between them along the plotted line represents their frequency delta.
|
||||||
|
|
||||||
### Estimated similarity and mechanical issues indicator
|
### Estimated similarity and mechanical issues indicator
|
||||||
|
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ function check_download {
|
|||||||
|
|
||||||
if [ ! -d "${K_SHAKETUNE_PATH}" ]; then
|
if [ ! -d "${K_SHAKETUNE_PATH}" ]; then
|
||||||
echo "[DOWNLOAD] Downloading Klippain Shake&Tune module repository..."
|
echo "[DOWNLOAD] Downloading Klippain Shake&Tune module repository..."
|
||||||
if git -C $shaketunedirname clone https://github.com/Frix-x/klippain-shaketune.git $shaketunebasename; then
|
if git -C $shaketunedirname clone https://cloud.reijii.org/gitea/reijii/klippain-shaketune-telegramm.git $shaketunebasename; then
|
||||||
chmod +x ${K_SHAKETUNE_PATH}/install.sh
|
chmod +x ${K_SHAKETUNE_PATH}/install.sh
|
||||||
printf "[DOWNLOAD] Download complete!\n\n"
|
printf "[DOWNLOAD] Download complete!\n\n"
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
|
|
||||||
## Klippain Shake&Tune automatic update management
|
## Klippain Shake&Tune automatic update management
|
||||||
[update_manager Klippain-ShakeTune]
|
[update_manager Klippain-ShakeTune]
|
||||||
type: git_repo
|
type: git_repo
|
||||||
origin: https://github.com/Frix-x/klippain-shaketune.git
|
origin: https://cloud.reijii.org/gitea/reijii/klippain-shaketune-telegramm.git
|
||||||
path: ~/klippain_shaketune
|
path: ~/klippain_shaketune
|
||||||
virtualenv: ~/klippy-env
|
virtualenv: ~/klippy-env
|
||||||
requirements: requirements.txt
|
requirements: requirements.txt
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "Shake&Tune"
|
name = "shake_n_tune"
|
||||||
description = "Klipper streamlined input shaper workflow and calibration tools"
|
description = "Klipper streamlined input shaper workflow and calibration tools"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">= 3.9"
|
requires-python = ">= 3.9"
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import matplotlib.font_manager
|
|||||||
import matplotlib.pyplot as plt
|
import matplotlib.pyplot as plt
|
||||||
import matplotlib.ticker
|
import matplotlib.ticker
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
from scipy.stats import pearsonr
|
||||||
|
|
||||||
matplotlib.use('Agg')
|
matplotlib.use('Agg')
|
||||||
|
|
||||||
@@ -210,8 +211,8 @@ def plot_compare_frequency(
|
|||||||
ax: plt.Axes, signal1: SignalData, signal2: SignalData, signal1_belt: str, signal2_belt: str, max_freq: float
|
ax: plt.Axes, signal1: SignalData, signal2: SignalData, signal1_belt: str, signal2_belt: str, max_freq: float
|
||||||
) -> None:
|
) -> None:
|
||||||
# Plot the two belts PSD signals
|
# Plot the two belts PSD signals
|
||||||
ax.plot(signal1.freqs, signal1.psd, label='Belt ' + signal1_belt, color=KLIPPAIN_COLORS['purple'])
|
ax.plot(signal1.freqs, signal1.psd, label='Belt ' + signal1_belt, color=KLIPPAIN_COLORS['orange'])
|
||||||
ax.plot(signal2.freqs, signal2.psd, label='Belt ' + signal2_belt, color=KLIPPAIN_COLORS['orange'])
|
ax.plot(signal2.freqs, signal2.psd, label='Belt ' + signal2_belt, color=KLIPPAIN_COLORS['purple'])
|
||||||
|
|
||||||
psd_highest_max = max(signal1.psd.max(), signal2.psd.max())
|
psd_highest_max = max(signal1.psd.max(), signal2.psd.max())
|
||||||
|
|
||||||
@@ -343,14 +344,12 @@ def plot_versus_belts(
|
|||||||
common_freqs: np.ndarray,
|
common_freqs: np.ndarray,
|
||||||
signal1: SignalData,
|
signal1: SignalData,
|
||||||
signal2: SignalData,
|
signal2: SignalData,
|
||||||
interp_psd1: np.ndarray,
|
|
||||||
interp_psd2: np.ndarray,
|
|
||||||
signal1_belt: str,
|
signal1_belt: str,
|
||||||
signal2_belt: str,
|
signal2_belt: str,
|
||||||
) -> None:
|
) -> None:
|
||||||
ax.set_title('Cross-belts comparison plot', fontsize=14, color=KLIPPAIN_COLORS['dark_orange'], weight='bold')
|
ax.set_title('Cross-belts comparison plot', fontsize=14, color=KLIPPAIN_COLORS['dark_orange'], weight='bold')
|
||||||
|
|
||||||
max_psd = max(np.max(interp_psd1), np.max(interp_psd2))
|
max_psd = max(np.max(signal1.psd), np.max(signal2.psd))
|
||||||
ideal_line = np.linspace(0, max_psd * 1.1, 500)
|
ideal_line = np.linspace(0, max_psd * 1.1, 500)
|
||||||
green_boundary = ideal_line + (0.35 * max_psd * np.exp(-ideal_line / (0.6 * max_psd)))
|
green_boundary = ideal_line + (0.35 * max_psd * np.exp(-ideal_line / (0.6 * max_psd)))
|
||||||
ax.fill_betweenx(ideal_line, ideal_line, green_boundary, color='green', alpha=0.15)
|
ax.fill_betweenx(ideal_line, ideal_line, green_boundary, color='green', alpha=0.15)
|
||||||
@@ -364,8 +363,8 @@ def plot_versus_belts(
|
|||||||
linewidth=2,
|
linewidth=2,
|
||||||
)
|
)
|
||||||
|
|
||||||
ax.plot(interp_psd1, interp_psd2, color='dimgrey', marker='o', markersize=1.5)
|
ax.plot(signal1.psd, signal2.psd, color='dimgrey', marker='o', markersize=1.5)
|
||||||
ax.fill_betweenx(interp_psd2, interp_psd1, color=KLIPPAIN_COLORS['red_pink'], alpha=0.1)
|
ax.fill_betweenx(signal2.psd, signal1.psd, color=KLIPPAIN_COLORS['red_pink'], alpha=0.1)
|
||||||
|
|
||||||
paired_peak_count = 0
|
paired_peak_count = 0
|
||||||
unpaired_peak_count = 0
|
unpaired_peak_count = 0
|
||||||
@@ -374,31 +373,27 @@ def plot_versus_belts(
|
|||||||
label = ALPHABET[paired_peak_count]
|
label = ALPHABET[paired_peak_count]
|
||||||
freq1 = signal1.freqs[peak1[0]]
|
freq1 = signal1.freqs[peak1[0]]
|
||||||
freq2 = signal2.freqs[peak2[0]]
|
freq2 = signal2.freqs[peak2[0]]
|
||||||
nearest_idx1 = np.argmin(np.abs(common_freqs - freq1))
|
|
||||||
nearest_idx2 = np.argmin(np.abs(common_freqs - freq2))
|
|
||||||
|
|
||||||
if nearest_idx1 == nearest_idx2:
|
if abs(freq1 - freq2) < 1:
|
||||||
psd1_peak_value = interp_psd1[nearest_idx1]
|
ax.plot(signal1.psd[peak1[0]], signal2.psd[peak2[0]], marker='o', color='black', markersize=7)
|
||||||
psd2_peak_value = interp_psd2[nearest_idx1]
|
|
||||||
ax.plot(psd1_peak_value, psd2_peak_value, marker='o', color='black', markersize=7)
|
|
||||||
ax.annotate(
|
ax.annotate(
|
||||||
f'{label}1/{label}2',
|
f'{label}1/{label}2',
|
||||||
(psd1_peak_value, psd2_peak_value),
|
(signal1.psd[peak1[0]], signal2.psd[peak2[0]]),
|
||||||
textcoords='offset points',
|
textcoords='offset points',
|
||||||
xytext=(-7, 7),
|
xytext=(-7, 7),
|
||||||
fontsize=13,
|
fontsize=13,
|
||||||
color='black',
|
color='black',
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
psd1_peak_value = interp_psd1[nearest_idx1]
|
ax.plot(
|
||||||
psd1_on_peak = interp_psd1[nearest_idx2]
|
signal1.psd[peak2[0]], signal2.psd[peak2[0]], marker='o', color=KLIPPAIN_COLORS['orange'], markersize=7
|
||||||
psd2_peak_value = interp_psd2[nearest_idx2]
|
)
|
||||||
psd2_on_peak = interp_psd2[nearest_idx1]
|
ax.plot(
|
||||||
ax.plot(psd1_on_peak, psd2_peak_value, marker='o', color=KLIPPAIN_COLORS['orange'], markersize=7)
|
signal1.psd[peak1[0]], signal2.psd[peak1[0]], marker='o', color=KLIPPAIN_COLORS['purple'], markersize=7
|
||||||
ax.plot(psd1_peak_value, psd2_on_peak, marker='o', color=KLIPPAIN_COLORS['purple'], markersize=7)
|
)
|
||||||
ax.annotate(
|
ax.annotate(
|
||||||
f'{label}1',
|
f'{label}1',
|
||||||
(psd1_peak_value, psd2_on_peak),
|
(signal1.psd[peak1[0]], signal2.psd[peak1[0]]),
|
||||||
textcoords='offset points',
|
textcoords='offset points',
|
||||||
xytext=(0, 7),
|
xytext=(0, 7),
|
||||||
fontsize=13,
|
fontsize=13,
|
||||||
@@ -406,7 +401,7 @@ def plot_versus_belts(
|
|||||||
)
|
)
|
||||||
ax.annotate(
|
ax.annotate(
|
||||||
f'{label}2',
|
f'{label}2',
|
||||||
(psd1_on_peak, psd2_peak_value),
|
(signal1.psd[peak2[0]], signal2.psd[peak2[0]]),
|
||||||
textcoords='offset points',
|
textcoords='offset points',
|
||||||
xytext=(0, 7),
|
xytext=(0, 7),
|
||||||
fontsize=13,
|
fontsize=13,
|
||||||
@@ -415,16 +410,12 @@ def plot_versus_belts(
|
|||||||
paired_peak_count += 1
|
paired_peak_count += 1
|
||||||
|
|
||||||
for _, peak_index in enumerate(signal1.unpaired_peaks):
|
for _, peak_index in enumerate(signal1.unpaired_peaks):
|
||||||
freq1 = signal1.freqs[peak_index]
|
ax.plot(
|
||||||
freq2 = signal2.freqs[peak_index]
|
signal1.psd[peak_index], signal2.psd[peak_index], marker='o', color=KLIPPAIN_COLORS['purple'], markersize=7
|
||||||
nearest_idx1 = np.argmin(np.abs(common_freqs - freq1))
|
)
|
||||||
nearest_idx2 = np.argmin(np.abs(common_freqs - freq2))
|
|
||||||
psd1_peak_value = interp_psd1[nearest_idx1]
|
|
||||||
psd2_peak_value = interp_psd2[nearest_idx1]
|
|
||||||
ax.plot(psd1_peak_value, psd2_peak_value, marker='o', color=KLIPPAIN_COLORS['purple'], markersize=7)
|
|
||||||
ax.annotate(
|
ax.annotate(
|
||||||
str(unpaired_peak_count + 1),
|
str(unpaired_peak_count + 1),
|
||||||
(psd1_peak_value, psd2_peak_value),
|
(signal1.psd[peak_index], signal2.psd[peak_index]),
|
||||||
textcoords='offset points',
|
textcoords='offset points',
|
||||||
fontsize=13,
|
fontsize=13,
|
||||||
weight='bold',
|
weight='bold',
|
||||||
@@ -434,16 +425,12 @@ def plot_versus_belts(
|
|||||||
unpaired_peak_count += 1
|
unpaired_peak_count += 1
|
||||||
|
|
||||||
for _, peak_index in enumerate(signal2.unpaired_peaks):
|
for _, peak_index in enumerate(signal2.unpaired_peaks):
|
||||||
freq1 = signal1.freqs[peak_index]
|
ax.plot(
|
||||||
freq2 = signal2.freqs[peak_index]
|
signal1.psd[peak_index], signal2.psd[peak_index], marker='o', color=KLIPPAIN_COLORS['orange'], markersize=7
|
||||||
nearest_idx1 = np.argmin(np.abs(common_freqs - freq1))
|
)
|
||||||
nearest_idx2 = np.argmin(np.abs(common_freqs - freq2))
|
|
||||||
psd1_peak_value = interp_psd1[nearest_idx1]
|
|
||||||
psd2_peak_value = interp_psd2[nearest_idx1]
|
|
||||||
ax.plot(psd1_peak_value, psd2_peak_value, marker='o', color=KLIPPAIN_COLORS['orange'], markersize=7)
|
|
||||||
ax.annotate(
|
ax.annotate(
|
||||||
str(unpaired_peak_count + 1),
|
str(unpaired_peak_count + 1),
|
||||||
(psd1_peak_value, psd2_peak_value),
|
(signal1.psd[peak_index], signal2.psd[peak_index]),
|
||||||
textcoords='offset points',
|
textcoords='offset points',
|
||||||
fontsize=13,
|
fontsize=13,
|
||||||
weight='bold',
|
weight='bold',
|
||||||
@@ -476,16 +463,21 @@ def plot_versus_belts(
|
|||||||
|
|
||||||
|
|
||||||
# Original Klipper function to get the PSD data of a raw accelerometer signal
|
# Original Klipper function to get the PSD data of a raw accelerometer signal
|
||||||
def compute_signal_data(data: np.ndarray, max_freq: float) -> SignalData:
|
def compute_signal_data(data: np.ndarray, common_freqs: np.ndarray, max_freq: float) -> SignalData:
|
||||||
helper = shaper_calibrate.ShaperCalibrate(printer=None)
|
helper = shaper_calibrate.ShaperCalibrate(printer=None)
|
||||||
calibration_data = helper.process_accelerometer_data(data)
|
calibration_data = helper.process_accelerometer_data(data)
|
||||||
|
|
||||||
freqs = calibration_data.freq_bins[calibration_data.freq_bins <= max_freq]
|
freqs = calibration_data.freq_bins[calibration_data.freq_bins <= max_freq]
|
||||||
psd = calibration_data.get_psd('all')[calibration_data.freq_bins <= max_freq]
|
psd = calibration_data.get_psd('all')[calibration_data.freq_bins <= max_freq]
|
||||||
|
|
||||||
_, peaks, _ = detect_peaks(psd, freqs, PEAKS_DETECTION_THRESHOLD * psd.max())
|
# Re-interpolate the PSD signal to a common frequency range to be able to plot them one against the other
|
||||||
|
interp_psd = np.interp(common_freqs, freqs, psd)
|
||||||
|
|
||||||
return SignalData(freqs=freqs, psd=psd, peaks=peaks)
|
_, peaks, _ = detect_peaks(
|
||||||
|
interp_psd, common_freqs, PEAKS_DETECTION_THRESHOLD * interp_psd.max(), window_size=20, vicinity=15
|
||||||
|
)
|
||||||
|
|
||||||
|
return SignalData(freqs=common_freqs, psd=interp_psd, peaks=peaks)
|
||||||
|
|
||||||
|
|
||||||
######################################################################
|
######################################################################
|
||||||
@@ -517,8 +509,9 @@ def belts_calibration(
|
|||||||
signal2_belt += belt_info.get(signal2_belt, '')
|
signal2_belt += belt_info.get(signal2_belt, '')
|
||||||
|
|
||||||
# Compute calibration data for the two datasets with automatic peaks detection
|
# Compute calibration data for the two datasets with automatic peaks detection
|
||||||
signal1 = compute_signal_data(datas[0], max_freq)
|
common_freqs = np.linspace(0, max_freq, 500)
|
||||||
signal2 = compute_signal_data(datas[1], max_freq)
|
signal1 = compute_signal_data(datas[0], common_freqs, max_freq)
|
||||||
|
signal2 = compute_signal_data(datas[1], common_freqs, max_freq)
|
||||||
del datas
|
del datas
|
||||||
|
|
||||||
# Pair the peaks across the two datasets
|
# Pair the peaks across the two datasets
|
||||||
@@ -526,18 +519,13 @@ def belts_calibration(
|
|||||||
signal1 = signal1._replace(paired_peaks=pairing_result.paired_peaks, unpaired_peaks=pairing_result.unpaired_peaks1)
|
signal1 = signal1._replace(paired_peaks=pairing_result.paired_peaks, unpaired_peaks=pairing_result.unpaired_peaks1)
|
||||||
signal2 = signal2._replace(paired_peaks=pairing_result.paired_peaks, unpaired_peaks=pairing_result.unpaired_peaks2)
|
signal2 = signal2._replace(paired_peaks=pairing_result.paired_peaks, unpaired_peaks=pairing_result.unpaired_peaks2)
|
||||||
|
|
||||||
# Re-interpolate the PSD signals to a common frequency range to be able to plot them one against the other point by point
|
# R² proved to be pretty instable to compute the similarity between the two belts
|
||||||
common_freqs = np.linspace(0, max_freq, 500)
|
# So now, we use the Pearson correlation coefficient to compute the similarity
|
||||||
interp_psd1 = np.interp(common_freqs, signal1.freqs, signal1.psd)
|
correlation, _ = pearsonr(signal1.psd, signal2.psd)
|
||||||
interp_psd2 = np.interp(common_freqs, signal2.freqs, signal2.psd)
|
similarity_factor = correlation * 100
|
||||||
|
similarity_factor = np.clip(similarity_factor, 0, 100)
|
||||||
# Calculating R^2 to y=x line to compute the similarity between the two belts
|
|
||||||
ss_res = np.sum((interp_psd2 - interp_psd1) ** 2)
|
|
||||||
ss_tot = np.sum((interp_psd2 - np.mean(interp_psd2)) ** 2)
|
|
||||||
similarity_factor = (1 - (ss_res / ss_tot)) * 100
|
|
||||||
ConsoleOutput.print(f'Belts estimated similarity: {similarity_factor:.1f}%')
|
ConsoleOutput.print(f'Belts estimated similarity: {similarity_factor:.1f}%')
|
||||||
|
|
||||||
# mhi = compute_mhi(similarity_factor, num_peaks, num_unpaired_peaks)
|
|
||||||
mhi = compute_mhi(similarity_factor, signal1, signal2)
|
mhi = compute_mhi(similarity_factor, signal1, signal2)
|
||||||
ConsoleOutput.print(f'[experimental] Mechanical health: {mhi}')
|
ConsoleOutput.print(f'[experimental] Mechanical health: {mhi}')
|
||||||
|
|
||||||
@@ -582,11 +570,11 @@ def belts_calibration(
|
|||||||
|
|
||||||
# Add the accel_per_hz value to the title
|
# Add the accel_per_hz value to the title
|
||||||
title_line5 = f'| Accel per Hz used: {accel_per_hz} mm/s²/Hz'
|
title_line5 = f'| Accel per Hz used: {accel_per_hz} mm/s²/Hz'
|
||||||
fig.text(0.55, 0.915, title_line5, ha='left', va='top', fontsize=14, color=KLIPPAIN_COLORS['dark_purple'])
|
fig.text(0.551, 0.915, title_line5, ha='left', va='top', fontsize=10, color=KLIPPAIN_COLORS['dark_purple'])
|
||||||
|
|
||||||
# Plot the graphs
|
# Plot the graphs
|
||||||
plot_compare_frequency(ax1, signal1, signal2, signal1_belt, signal2_belt, max_freq)
|
plot_compare_frequency(ax1, signal1, signal2, signal1_belt, signal2_belt, max_freq)
|
||||||
plot_versus_belts(ax3, common_freqs, signal1, signal2, interp_psd1, interp_psd2, signal1_belt, signal2_belt)
|
plot_versus_belts(ax3, common_freqs, signal1, signal2, signal1_belt, signal2_belt)
|
||||||
|
|
||||||
# Adding a small Klippain logo to the top left corner of the figure
|
# Adding a small Klippain logo to the top left corner of the figure
|
||||||
ax_logo = fig.add_axes([0.001, 0.894, 0.105, 0.105], anchor='NW')
|
ax_logo = fig.add_axes([0.001, 0.894, 0.105, 0.105], anchor='NW')
|
||||||
|
|||||||
@@ -34,13 +34,6 @@ IN_DANGER = False
|
|||||||
|
|
||||||
class ShakeTune:
|
class ShakeTune:
|
||||||
def __init__(self, config) -> None:
|
def __init__(self, config) -> None:
|
||||||
try:
|
|
||||||
from extras.danger_options import get_danger_options
|
|
||||||
|
|
||||||
IN_DANGER = True # check if Shake&Tune is running in DangerKlipper
|
|
||||||
except ImportError:
|
|
||||||
continue
|
|
||||||
|
|
||||||
self._pconfig = config
|
self._pconfig = config
|
||||||
self._printer = config.get_printer()
|
self._printer = config.get_printer()
|
||||||
gcode = self._printer.lookup_object('gcode')
|
gcode = self._printer.lookup_object('gcode')
|
||||||
|
|||||||
Reference in New Issue
Block a user