Calcolo del PDF di una forma d'onda dai suoi campioni


27

Qualche tempo fa stavo provando diversi modi per disegnare forme d'onda digitali e una delle cose che ho provato è stata, invece della sagoma standard dell'inviluppo dell'ampiezza, mostrarla più come un oscilloscopio. Ecco come si presenta un'onda sinusoidale e quadrata su un ambito:

inserisci qui la descrizione dell'immagine

Il modo ingenuo per farlo è:

  1. Dividi il file audio in un blocco per pixel orizzontale nell'immagine di output
  2. Calcola l'istogramma delle ampiezze di campionamento per ogni blocco
  3. Traccia l'istogramma in base alla luminosità come una colonna di pixel

Produce qualcosa del genere: inserisci qui la descrizione dell'immagine

Funziona bene se ci sono molti campioni per blocco e la frequenza del segnale non è correlata alla frequenza di campionamento, ma non altrimenti. Se la frequenza del segnale è un sottomultiplo esatto della frequenza di campionamento, ad esempio, i campioni si verificheranno sempre esattamente alle stesse ampiezze in ciascun ciclo e l'istogramma sarà solo di alcuni punti, anche se il segnale ricostruito effettivo esiste tra questi punti. Questo impulso sinusoidale dovrebbe essere regolare come quello in alto a sinistra, ma non è perché è esattamente 1 kHz e i campioni si verificano sempre attorno agli stessi punti:

inserisci qui la descrizione dell'immagine

Ho provato il upsampling per aumentare il numero di punti, ma non risolve il problema, in alcuni casi aiuta solo a chiarire le cose.

Quindi quello che mi piacerebbe davvero è un modo per calcolare il vero PDF (probabilità vs ampiezza) del segnale continuo ricostruito dai suoi campioni digitali (ampiezza vs tempo). Non so quale algoritmo usare per questo. In generale, il PDF di una funzione è la derivata della sua funzione inversa .

PDF di sin (x):ddxarcsinx=11x2

Ma non so come calcolare questo per le onde in cui l'inverso è una funzione multivalore , o come farlo velocemente. Suddividilo in rami e calcola l'inverso di ciascuno, prendi i derivati ​​e sommali tutti insieme? Ma è piuttosto complicato e probabilmente c'è un modo più semplice.

Questo "PDF di dati interpolati" si applica anche al tentativo che ho fatto di fare una stima della densità del kernel di una traccia GPS. Avrebbe dovuto essere a forma di anello, ma poiché stava solo guardando i campioni e non considerando i punti interpolati tra i campioni, il KDE sembrava più una gobba che un anello. Se i campioni sono tutto ciò che sappiamo, allora questo è il meglio che possiamo fare. Ma i campioni non sono tutto ciò che sappiamo. Sappiamo anche che esiste un percorso tra i campioni. Per il GPS, non esiste una ricostruzione Nyquist perfetta come per l'audio bandlimited, ma l'idea di base si applica ancora, con alcune congetture nella funzione di interpolazione.


Hai un esempio di una funzione multivalore che ti interessa? Probabilmente dovrai valutarlo lungo una diramazione che ha più senso per i tuoi dati fisici.
Lorem Ipsum,

Sei più interessato ai modi per disegnare quel tipo di trama, o la trama è solo una motivazione per la domanda sul calcolo del PDF?
datageist

@yoda: Bene, la funzione sopra per l'onda sinusoidale si trova prendendo solo mezzo ciclo, invertendo e prendendo la derivata, perché ogni mezzo ciclo ha lo stesso PDF del successivo. Ma per ottenere il valore per un intero segnale audio arbitrario, non puoi fare questo presupposto. Penso che dovresti dividerlo in "tagli di rami", prendere il PDF di ciascuno a sua volta e sommarli tutti insieme?
endolith,

@datageist: Hmm. Sono interessato ai modi per disegnare quel tipo di trama, ma quel tipo di trama è il PDF. Un collegamento che produce lo stesso risultato o molto simile è ok.
endolith,

@endolith, oh sì, ho capito. Solo una domanda sull'enfasi davvero (cioè quali tipi di scorciatoie sono ragionevoli).
datageist

Risposte:


7

Interpolare a più volte la frequenza originale (ad esempio 8 volte sovracampionato). Ciò consente di assumere un segnale lineare a tratti. Questo segnale avrà pochissimo errore rispetto alla risoluzione infinita, interpolazione sin (x) / x continua della forma d'onda.

Supponiamo che ogni coppia di valori sovracampionati abbia una linea continua da un valore all'altro. Usa tutti i valori tra. Questo ti dà una fetta orizzontale sottile da y1 a y2 da accumulare in un PDF di risoluzione arbitraria. Ogni sezione rettangolare di probabilità deve essere ridimensionata in un'area 1 / nsamples.

L'uso della linea tra i campioni anziché il campione stesso impedisce un PDF "spikey", anche nel caso in cui vi sia una relazione fondamentale tra il periodo di campionamento e la forma d'onda.


Ho scritto una funzione per l'istogramma interpolato linearmente, ma è complicato. Conosci il codice esistente per questo?
endolito il

L'interpolazione lineare fa un'enorme differenza per la maggior parte delle forme d'onda, anche senza il sovracampionamento. Il seno da 1 kHz ora sembra quasi il seno di 997 Hz. Invece di solo linee orizzontali ai valori del campione, ora sono strisce orizzontali di colore tra di loro. Con il sovracampionamento, anche le bande vengono smussate. Con il ricampionamento FFT e alcune sovrapposizioni con blocchi adiacenti, dovrei essere in grado di raggiungere i picchi reali tra campioni. Devo rendere il mio codice istogramma interpolato più veloce, però ...
Endolith,

Ho completamente riscritto il mio script per questo, e penso che ho avuto l'istogramma e antialiasing destra questa volta: gist.github.com/endolith/652d3ba1a68b629ed328
endolith

L'ultima versione è su github.com/endolith/scopeplot
endolith il

7

Quello che vorrei fare è essenzialmente il "ricampionatore casuale" di Jason R, che a sua volta è un'implementazione basata su segnale pre-campionato del campionamento stocastico di yoda.

Ho usato l'interpolazione cubica semplice per un punto casuale tra ogni due campioni. Per un suono synth primitivo (in decomposizione da un segnale quadrato non bandlimited saturato + persino armoniche a un seno) sembra questo:

Synth PDF ricampionato casualmente

Confrontiamolo con una versione con campionamento superiore,

inserisci qui la descrizione dell'immagine

e quello strano con lo stesso campionatore ma nessuna interpolazione.

inserisci qui la descrizione dell'immagine

Notevole artefatto di questo metodo è il superamento nel dominio di tipo quadrato, ma in realtà è anche l'aspetto del PDF del segnale sinc-filtered (come ho detto, il mio segnale non è bandlimited) e rappresenta molto meglio il volume percepito rispetto ai picchi, se questo fosse un segnale audio.

Codice (Haskell):

cubInterpolate vll vl v vr vrr vrrr x
    = v*lSpline x + vr*rSpline x
      + ((vr-vl) - (vrr-vll)/4)*ldSpline x
      + ((vrr-v) - (vrrr-vl)/4)*rdSpline x
     where lSpline x = rSpline (1-x)
           rSpline x = x*x * (3-2*x)
           ldSpline x = x * (1 + x*(x-2))
           rdSpline x = -ldSpline (1-x)

                   --  rand list   IN samples  OUT samples
stochasticAntiAlias :: [Double] -> [Double] -> [Double]
stochasticAntiAlias rs (lsll:lsl:lsc:lsr:lsrr:[]) = []
stochasticAntiAlias (r:rLst) (lsll:lsl:lsc:lsr:lsrr:lsrrr:t)
    = ( cubInterpolate lsll lsl lsc lsr lsrr lsrrr r )
          : stochasticAntiAlias rLst (lsll:lsl:lsc:lsr:lsrr:lsrrr:t)

rand list è un elenco di variabili casuali nell'intervallo [0,1].


1
Sembra stupendo. +1 per il codice Haskell.
datageist

Sì, dovrebbe superare i valori di esempio. In realtà ho pianificato di avere un valore di picco anche per ogni colonna di pixel, possibilmente disegnata in modo diverso, in base ai picchi di intersample massimo e non solo ai campioni di max. Forme d'onda come flic.kr/p/7QAScX mostrano perché questo è necessario.
endolith,

Per "versione con campionamento superiore" intendi che è sottocampionato, ma ancora uniformemente campionato? E quelli sono i punti blu?
endolith

1
@endolith È semplicemente la forma d'onda originale calcolata in primo luogo con una frequenza di campionamento più elevata. Essenzialmente come i punti blu rappresentano un suono campionato a 192 kHz, e quelli gialli più in basso rappresentano un downsample fatto in modo ingenuo a 24 kHz. I punti gialli superiori sono stochasticAntiAliasdi questo. Ma la versione con campionamento più elevato è in effetti un tasso uniforme in entrambi i casi.
leftaroundabout

5

Mentre il tuo approccio è teoricamente corretto (e deve essere leggermente modificato per le funzioni non monotoniche), è estremamente difficile calcolare l'inverso di una funzione generica. Come dici tu, dovrai occuparti dei punti e dei tagli delle filiali, il che è fattibile, ma seriamente non vorrai.

Come già accennato, il campionamento regolare campiona lo stesso insieme di punti e come tale è altamente suscettibile alle stime scarse nelle regioni in cui non campiona (anche se il criterio di Nyquist è soddisfatto). In questo caso, il campionamento per un periodo più lungo non aiuta neanche.

In generale, quando si ha a che fare con funzioni di densità di probabilità e istogrammi, è un'idea molto migliore pensare in termini di campionamento stocastico rispetto al campionamento normale (vedere la risposta collegata per un'introduzione). Campionando stocasticamente, puoi assicurarti che ogni punto abbia la stessa probabilità di essere "colpito" ed è un modo molto migliore per stimare il pdf.

Ecco un esempio: considera la funzione . Ora, se lo con una frequenza di campionamento Hz (frequenza di Nyquist, Hz), la densità di probabilità risultante è il diagramma a sinistra (401 bin allineati tra -2 e 2). Non importa se eseguo il campionamento per 10 secondi o 100. Rimane sempre lo stesso. D'altra parte, campionare stocasticamente ad una frequenza di campioni (distribuzione uniforme) al secondo (non sto usando Hz qui, perché ciò implica un significato diverso) per 30 secondi dà il diagramma sulla destra (stesso binning).f(x)=sin(20πx)+sin(100πx)f N = 100 1000fs=1000fN=1001000

Si può facilmente vedere che sebbene sia rumoroso, è un'approssimazione molto migliore al PDF effettivo rispetto a quello sulla destra che mostra gli zeri in diversi intervalli e errori di grandi dimensioni in molti altri. Avendo un tempo di osservazione più lungo, è possibile ridurre la varianza in quella a destra, eventualmente convergere nel PDF esatto (linea nera tratteggiata) nel limite di osservazioni di grandi dimensioni.

inserisci qui la descrizione dell'immagine


1
"è estremamente difficile calcolare l'inverso di una funzione generica" ​​Bene, questa non è una funzione tanto quanto una serie di campioni, quindi trovare l'inverso sta semplicemente scambiando le coordinate xey dei campioni e quindi ricampionando per adattarsi il nuovo sistema di coordinate. Non posso comunque cambiare il campionamento. Stiamo parlando di dati preesistenti creati utilizzando un campionamento uniforme.
endolith,

4

Stima della densità del kernel

Un modo per stimare il PDF di una forma d'onda è usare uno stimatore della densità del kernel .

Questo prende tutti i tuoi campioni e una funzione del kernel (ad es. Un gaussiano), e li avvolge con (il delta di Dirac) per fornire una stima del PDF, :x(n)K(x)δ(xx(n))P^

P^(x)=n=0NK(xx(n))

Aggiornamento: informazioni aggiuntive interessanti.

Supponiamo di avere il segnale per , quindi --- come dici --- puoi anche conoscere il suo DFT :x(n)n=0,1,...,N1X(k)

X(k)=n=0N1x(n)eȷ2πnk/N

In modo che sia il coefficiente di :X(k)eȷ2πnk/N

x(n)=1Nk=0N1X(k)eȷ2πnk/N

Quindi un'ipotesi di ciò che potresti essere dopo è di coinvolgere tutti i PDF di ciascun componente di Fourier insieme:

|X(k)|11x2

Tuttavia, ciò non tiene conto del modo in cui la fase di contribuisce (o meno) all'aggiunta in .x ( n )X(k)x(n)

Ci vuole più pensiero, però!


Ci ho pensato, ma la stima della densità viene utilizzata per stimare una funzione di densità di probabilità sconosciuta . A causa del teorema del campionamento di Nyquist, l'intera forma d'onda è nota, esattamente, e anche l'esatta funzione di densità di probabilità dovrebbe essere nota. Sto bene con la stima se si tratta di un compromesso tra velocità e precisione, ma deve esserci un modo per estrarre il PDF reale da esso. Ad esempio, è possibile creare una forma d'onda ricostruita inserendo una funzione sinc in ciascun campione e sommandoli insieme. È possibile creare il PDF utilizzando il PDF di una funzione sinc come kernel? Non penso che funzioni così.
endolith,

Ad esempio, non penso che questo risolva il problema in cui i campioni di segnale sono un sottomultiplo della frequenza di campionamento. Non tiene conto della forma d'onda ricostruita tra i campioni, vero? Sfoca semplicemente ogni punto del PDF per cercare di colmare le lacune. Ho avuto un problema simile con il tentativo di fare una stima della densità del kernel di una traccia GPS, perché non tiene conto dei valori tra i campioni.
endolith,

4

Come hai indicato in uno dei tuoi commenti, sarebbe interessante poter calcolare l'istogramma del segnale ricostruito usando solo i campioni e il PDF della funzione sinc che interpola i segnali bandlimited. Sfortunatamente, non penso che ciò sia possibile perché l'istogramma del sinc non ha tutte le informazioni che ha il segnale stesso; tutte le informazioni sulle posizioni nel dominio del tempo in cui viene rilevato ciascun valore vengono perse. Ciò rende impossibile modellare il modo in cui sommerebbero le versioni ridimensionate e ritardate del sinc, che è ciò che si vorrebbe al fine di calcolare l'istogramma della versione "continua" o campionata verso l'alto senza effettivamente fare il up-sampling.

Penso che ti sia rimasta l'interpolazione come l'opzione migliore. Hai indicato un paio di problemi che ti hanno impedito di voler fare questo, che penso possa essere affrontato:

  • Spese di calcolo: questa è ovviamente sempre una preoccupazione relativa, a seconda dell'applicazione specifica per cui si desidera utilizzarla. Sulla base del link che hai pubblicato nella galleria di rendering che hai raccolto, suppongo che tu voglia farlo per la visualizzazione dei segnali audio. Se sei interessato a questo per un'applicazione in tempo reale o offline, ti incoraggio a prototipare un interpolatore efficiente e vedere se è davvero troppo costoso. Il ricampionamento polifase è un buon modo per fare ciò che è flessibile (puoi usare qualsiasi fattore razionale).

  • Distorsione dai componenti periodici correlati razionalmente alla frequenza di campionamento: anche se non è possibile eliminarlo completamente, si dovrebbe essere in grado di mitigarlo in qualche modo interpolando uno "strano" fattore: invece di aumentare il campionamento di 4, provare 71/18 ( solo un esempio). Questa sarà una struttura un po 'più complicata, ma può ancora essere implementata in modo efficiente. Ciò fornirà una distribuzione più uniforme dei campioni tra i periodi di componenti con frequenze correlate alla frequenza di campionamento. In alternativa, utilizzare uno schema di ricampionamento che consente di selezionare un rapporto di ricampionamento arbitrario e quindi ricampionare con un numero (approssimativamente) irrazionale, come . Questo può essere fatto in modo efficiente utilizzando un interpolatore Farrow , che utilizza l'interpolazione polinomiale.π


E se la forma d'onda fosse a 44.1 / π kHz? :) Questo è un buon consiglio, comunque. Esiste qualcosa come il ricampionamento casuale? O davvero, immagino che ciò che funzionerebbe perfettamente sarebbe ricampionare in modo non uniforme, in modo tale che i nuovi campioni si adattino perfettamente ai contenitori nella dimensione y, invece di essere distribuiti uniformemente nella dimensione x. Non sono sicuro che ci sia un modo per farlo
endolith,

2
Si potrebbe facilmente implementare un ricampionatore "casuale" usando una struttura di Farrow. È uno schema che consente un ritardo arbitrario del campione frazionario interpolando usando polinomi (spesso cubici). È possibile mantenere un accumulatore di fase tra campioni, simile a quello utilizzato in un NCO , che viene incrementato da frazioni pseudocasuali di un intervallo di campionamento per ciascun campione di output (ricampionato). Il valore dell'accumulatore viene utilizzato come input per l'interpolatore di Farrow, definendo la quantità di ritardo frazionario per ciascuna uscita.
Jason R,

Hmm, per chiarire, Farrow è solo una versione ottimizzata per processore / memoria della vecchia interpolazione polinomiale regolare?
endolith,

1
Sì. È solo una struttura efficiente per l'implementazione del ritardo frazionario arbitrario basato sul polinomio.
Jason R,

L'interpolazione cubica è solo un'approssimazione. Voglio conoscere veri picchi tra campioni, e non sembra funzionare bene su picchi estremi: stackoverflow.com/questions/1851384/… In realtà, sembra che una serie infinita con una discontinuità come [..., -1, 1, -1, 1, 1, -1, 1, -1, ...] produrrà comunque un picco infinito tra campioni, quindi non sono sicuro di quanto ciò importerebbe in pratica.
endolith

0

È necessario attenuare l'istogramma (questo produrrà risultati simili a quelli dell'uso di un metodo kernel). È necessario sperimentare esattamente come eseguire il livellamento. Forse potrebbe essere fatto anche per interpolazione. Oltre al livellamento, credo che otterrai anche risultati migliori se esegui il upcampionamento della forma d'onda in modo tale che la frequenza di campionamento sia "significativamente più alta" rispetto alla frequenza più alta nel tuo input. Ciò dovrebbe aiutare nel caso "complicato" in cui un'onda sinusoidale è correlata alla frequenza di campionamento in modo tale da popolare solo pochi bin nell'istogramma. Se portata all'estremo, una frequenza di campionamento sufficientemente elevata dovrebbe darti delle belle trame senza livellamento. Quindi l'upsampling combinato con una sorta di smoothing dovrebbe produrre grafici migliori.

Dai un esempio di un tono da 1kHz, dove la trama non è come ti aspetti. Ecco la mia proposta (codice Matlab / Octave)

pixels_vertical = 100;
% This needs to be tuned to your configuration and acceptance
upsampling_factor = 16*(pixels_vertical/100); 
fs_original = 48000;
fsine = 1000; % in Hz
fs_up = upsampling_factor*fs_original;
duration = 1; % in seconds
x = sin(2*pi*fsine*[0:duration*fs_up]/fs_up);
period_in_samples = fs_up/fsine;
hist_points = linspace(-1,1,pixels_vertical);
istart = 1;
iend   = period_in_samples;
pixel_values = hist(x(istart:iend), hist_points);
% smooth pixel values
[b,a] = butter(2,0.2);
pixel_values_smooth = filtfilt(b,a,pixel_values);
figure;hold on;
plot(hist_points, pixel_values);
plot(hist_points, pixel_values_smooth,'r');

Per il tuo tono a 1000Hz ottieni questo inserisci qui la descrizione dell'immagine

Quello che devi fare è sintonizzare l'espressione upsampling_factor secondo le tue preferenze.

Ancora non sicuro al 100% di quali siano le tue esigenze. Ma usando il principio sopra di upsampling e smoothing otterrai questo per il tono 1kHz (realizzato con Matlab). Si noti che nell'istogramma non elaborato ci sono molti bin con zero hit.

inserisci qui la descrizione dell'immagine


Sì, ha davvero bisogno di un qualche tipo di interpolazione come parte dell'algoritmo. Il livellamento dell'istogramma da solo non lo farà, perché l'istogramma ha punti discreti, non la forma d'onda ricostruita. L'unico modo in cui funzionerebbe l'upsampling è se lo faccio al punto in cui ci sono molti più campioni rispetto ai pixel verticali, ma questo è un metodo di forza bruta pesante che richiede molto tempo.
endolith,

o calcolare l' effetto dell'interpolazione sull'output senza effettivamente interpolare
endolith
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.