Fenster um Peaks (Stoß) automatisch bestimmen: linke/rechte Seite variabel
19 vues (au cours des 30 derniers jours)
Afficher commentaires plus anciens
Eunika
le 17 Déc 2025 à 12:36
Réponse apportée : Ritam
le 23 Déc 2025 à 8:24
Hallo zusammen,
ich bin noch recht unerfahren in MATLAB und arbeite gerade an der Auswertung von abreinigenden Druckstößen in einer Filterpatrone (Gewebefilter). In der Patrone sind 12 Messstellen angeordnet. Pro Versuch gibt es mehrere kurze Druckstöße (Abreinigungspulse). Ziel ist, unterschiedliche Veränderungen an einem Bateil, zu vergleichen. Bewertet werden soll das über Druckspitzen und Druckimpulse (Integral über die Stoßdauer).
Da mich nur die Stöße interessieren, selektiere ich die Pulse zunächst in einem Referenzkanal mit findpeaks. Anschließend möchte ich für jeden gefundenen Peak ein Zeitfenster [i1:i2]definieren, um daraus für alle 12 Kanäle die Peakwerte und den Druckimpuls zu berechnen.
Mein Problem:
Die Stoßform ist je nach Messpunkt und Variante unterschiedlich (z. B. vorne niedrigere Amplituden als hinten), und dadurch ist die optimale linke/rechte Fenstergrenze nicht konstant. Wenn ich ein fixes Fenster nehme (z. B. ±0,1 s), schneide ich manchmal den Stoß ab oder integriere zu viel „Nicht-Stoß“-Signal.
Konkrete Frage:
Wie würdet ihr in MATLAB sauber und robust die Start- und Endindizes eines Pulses pro Peak bestimmen, sodass ich anschließend zuverlässig den Druckimpuls integrieren kann, ohne den Stoß abzuschneiden? Ich habe schon überlegt, die linke und rechte Seite dynamisch zu machen, aber an der Umsetzung hackst bei mir.
Und geht es noch diesen Code zu optimieren?
Zu verdeutlichung hier ist der code. Bitte tut mich nicht allzu judgen. Matlab fällt mir noch schwer.
clc
clear all
close all
%% Konstanten
f_sample = 100; % Abtastrate
ref_kanal = 1; % Referenzkanal innerhalb der Daten (1 = erste Spalte aus data_ch_all)
dt = 1/f_sample; % Zeitschritt
min_dist_s = 30; % minimaler Abstand zwischen den Stößen in s
min_prominence = 10; % minimale Abweichung für Stoßerkennung in Pa
linke_seite = 0.1; % links vom Peak in s
rechte_seite = 0.2; % rechts vom Peak in s
file_patterns = {
"AbstandkeinKegel_Kegel_Patrone_V1*.tdms"
"KegelKS_100Minus50_PositionZurPatrone_V1*.tdms"
"KegelSB_100Minus25_PositionZurPatrone_V1*.tdms"
"KegelKS_100Minus0_PositionZurPatrone_V1*.tdms"
"KegelKS_100Plus25_PositionZurPatrone*.tdms"
};
labels = {'kein Kegel','- 50 mm', '- 25 mm', '0 mm', '25 mm',}
nConf = numel(file_patterns);
colors = turbo(nConf);
%% Platzhalter
firstDone = false;
% Fenster in Samples
wL = round(linke_seite * f_sample);
wR = round(rechte_seite * f_sample);
for k = 1:nConf
fprintf('\n Auswertung %s \n', labels{k});
files = dir(file_patterns{k});
nFiles = numel(files);
if nFiles == 0
warning('Keine Dateien gefunden für Muster: %s', file_patterns{k});
continue
end
% Sammelvariablen
alle_Peaks = [];
alle_PI = [];
for i = 1:nFiles
%% Datei einlesen
fname = files(i).name;
data_cell = tdmsread(fname); % Datenspeicherung in Cell-Array
data_table = data_cell{1}; % Datenspeicherung in Table-Array
data_double = table2array(data_table); % Datenkonvertierung in Double-Format
% Zeitvektor berechnen
N = size(data_double,1); % Anzahl der Messpunkte
vec_t = (0:N-1)' / f_sample; % Zeitvektor in s
% Zuordnung zu den einzelnen Kanälen
data_ch_all = data_double(:,2:13);
nCh = size(data_ch_all,2);
% Stoßerkennung (auf Referenzkanal)
ref = data_ch_all(:, ref_kanal);
[pks, locs] = findpeaks(ref, ...
'MinPeakDistance', round(min_dist_s * f_sample), ...
'MinPeakProminence', min_prominence);
nStoss = numel(locs);
fprintf('Datei %d (%s): %d Stöße gefunden.\n', i, fname, nStoss)
peaks_this_file = nan(nStoss, nCh);
PI_this_file = nan(nStoss, nCh);
for s = 1:nStoss
i1 = max(1, locs(s) - wL);
i2 = min(N, locs(s) + wR);
seg = data_ch_all(i1:i2, :);
% Peak
peaks_this_file(s,:) = max((seg), [], 1, 'omitnan');
% Pressure impulse
PI_this_file(s,:) = sum(seg, 1, 'omitnan') * dt;
end
% Ergebnisse über alle Dateien dieser Messzeile sammeln
alle_Peaks = [alle_Peaks; peaks_this_file];
alle_PI = [alle_PI; PI_this_file];
end
% Auswertung Peakdruck ==> Mittelwert und Standardabweichung pro Kanal
peak_mean = mean(alle_Peaks, 1, 'omitnan');
peak_std = std( alle_Peaks, 0, 1, 'omitnan');
% Auswertung Pressure Impulse ==> Mittelwert und Standardabweichung pro Kanal
PI_mean = mean(alle_PI, 1, 'omitnan');
PI_std = std( alle_PI, 0, 1, 'omitnan');
% Berechnung von Jet-Intensity, C.V.
Jet_intensity = mean(peak_mean);
C_V = std(peak_mean) / Jet_intensity;
% Total Pressure Impulse pro Stoß (Summe über alle Kanäle)
TPI_per_stoss = sum(alle_PI, 2, 'omitnan');
TPI_mean = mean(TPI_per_stoss, 'omitnan');
TPI_std = std(TPI_per_stoss, 0, 'omitnan');
fprintf(' Jet-Intensity: %.2f Pa\n', Jet_intensity);
fprintf(' C.V.: %.3f\n', C_V);
fprintf(' mittlerer totaler Druckimpuls: %.2f Pa·s (Std: %.2f Pa·s)\n', ...
TPI_mean, TPI_std);
% Beim ersten Durchlauf Sammelmatrizen dimensionieren
if ~firstDone
peak_mean_all = nan(nConf, nCh);
peak_std_all = nan(nConf, nCh);
PI_mean_all = nan(nConf, nCh);
PI_std_all = nan(nConf, nCh);
Jet_intensity_all = nan(nConf, 1);
C_V_all = nan(nConf, 1);
TPI_mean_all = nan(nConf, 1);
TPI_std_all = nan(nConf, 1);
firstDone = true;
end
% Ergebnisse dieser Messzeile in Gesamtmatrizen schreiben
peak_mean_all(k,:) = peak_mean;
peak_std_all(k,:) = peak_std;
PI_mean_all(k,:) = PI_mean;
PI_std_all(k,:) = PI_std;
Jet_intensity_all(k,1) = Jet_intensity;
C_V_all(k,1) = C_V;
TPI_mean_all(k,1) = TPI_mean;
TPI_std_all(k,1) = TPI_std;
end
if ~firstDone
error('Es wurden keine gültigen Dateien ausgewertet. Bitte file_patterns prüfen.');
end
nCh = size(peak_mean_all,2);
x = 1:nCh;
0 commentaires
Réponse acceptée
Ritam
le 23 Déc 2025 à 8:24
A practical way to define pulse start/end indices is to combine several methods and choose what best fits your signal characteristics:
1. Use findpeaks widths (with WidthReference set to half‑height or half‑prominence) for simple, consistent left/right extents when pulse shapes are fairly uniform
2. Apply adaptive threshold crossing relative to a local baseline (e.g., moving median) with a threshold T to accommodate amplitude differences across channels or positions.
T = baseline + max(η . σ, γ . prominence)
3. Leverage slope/derivative zero‑crossings with hysteresis after smoothing (e.g., Savitzky–Golay) to identify the last pre‑peak rising point and first post‑peak decay point while avoiding noise retriggers
4. Use change‑point detection (e.g., findchangepts) locally around each peak as a fallback when thresholds are unreliable
5. Guard against overlaps by capping the end index at the midpoint to the next peak (or its detected start), whichever occurs sooner.
Each approach offers complementary strengths, favor widths for consistency, adaptive thresholds for robustness to variability, derivatives for precise timing, change‑points for ambiguous cases, and overlap guards for crowded events.
0 commentaires
Plus de réponses (0)
Voir également
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!