2015-07-06 24 views
5

Voglio trovare e azzerare i picchi in un vettore con la larghezza più breve, ovvero picchi che hanno un singolo campione diverso da zero ei campioni vicini zero, ovvero [0 ~0 0] con ~0 è il picco. Esempio: se x = [1 0 2 0 0 3 0 4 5 6 0 7 0 8], quindi voglio trovare il 2, 3 e 7 e renderli 0, cioè x diventa [1 0 0 0 0 0 0 4 5 6 0 0 0 8]. Il seguente codice fa il trucco, ma esiste un modo più efficiente o migliore per farlo, oppure esiste una funzione Matlab che trova un determinato pattern in un vettore (o anche in una matrice)?Metodo efficiente per trovare un valore circondato da zeri in un vettore

% remove peaks of shape [0 ~0 0] 
k = find(x); 
for j=k' 
    if j==numel(x) || j==1 
    elseif ~x(j-1) && ~x(j+1) 
     x(j) = 0; 
    end 
end 
+0

'X' può contenere sia numeri positivi che negativi? – Dan

+0

Per completezza, è possibile aggiungere anche l'output previsto relativo all'input di esempio. Altrimenti un ottimo [mcve] (http://stackoverflow.com/help/mcve) – kkuilla

risposta

8

Siete alla ricerca di elementi in cui la convoluzione con il kernel [1,1,1] non differiscono con l'originale. L'unica complicazione è che dobbiamo ignorare il caso limite:

x = [1 0 2 0 0 3 0 4 5 6 0 7 0 8]; 
y = conv(x,[1,1,1],'same'); 
ind = find(x==y); 
x(ind(2:end-1)) = 0 

o

x(find(x(2:end-1)==conv(x,[1,1,1],'valid'))+1) = 0 

se di fronte alla prospettiva di entrambi i numeri positivi e negativi, allora basata su suggerimento di Craigim nei commenti:

xx = abs(x); 
x(find(xx(2:end-1)==conv(xx,[1,1,1],'valid'))+1) = 0 
+1

In realtà - questo si interrompe se si accettano numeri negativi, cioè se 'x = [1 0 2 0 0 3 0 4 5 -4 0 7 0 8] 'allora questo metodo elimina anche il' 5'. È un problema per il tuo caso d'uso? – Dan

+4

Invece di convoluting con il vettore originale, convolute con 'xx = x ~ = 0 '. – craigim

+0

Questa risposta mi piace di più, perché volevo farlo con una convoluzione, ma mi ero convinto con [0 1 0], che praticamente non fa nulla. Convolgere con un array di 'n' quelli con' n' non uniforme rileverà un singolo picco di campionamento circondato da zeri '(n-1)/2'. Grazie! – Erik

5

Utilizzare conv (sulla falsariga della risposta di Dan) è probabilmente l'approccio migliore; ma può anche essere fatto con strfind:

x(strfind(x~=0, [0 1 0]) + 1) = 0; 

o utilizzando diff per calcolare la differenza di secondo ordine:

x(find(diff(~x, 2)==2) + 1) = 0; 
+0

La versione 'str' non funziona per me. 'error: strfind: PATTERN deve essere una stringa o una matrice di stringhe' – kkuilla

+0

@kkuilla Funziona in Matlab R2015a. Ma non mi sorprende che non funzioni in tutte le versioni, perché l'uso di 'strfind' con i numeri non è documentato. Che versione stai usando? –

+0

Al momento, GNU Octave Versione 3.8.1 :-( – kkuilla

5

qui sarebbe il mio modo per farlo

x_add = x(1:end-2) + x(2:end-1) + x(3:end); 
x(find([0,x(2:end-1)==x_add,0]))=0; 

E ' aggiunge il valore precedente e il valore successivo a ciascuno e controlla quale non è stato modificato

+0

Mi piace, grazie! Il codice è un po 'più difficile da leggere e quindi più difficile da capire rispetto alle altre soluzioni, ma è compatto e abbastanza intelligente. – Erik

Problemi correlati