xorg1990
New member
Hallo,
ich stehe mal wider vor einen Rätsel und zwar erhalte ich ein kein Ton sobald ich auf die Filterkoeffizienten das Hanning Fenster anwende.
Ein 2tes Problem ist das im Ton immer ein kleines knacken zu hören ist, das ist absolut nervig und macht auch dementsprechende Störungen im FFT Spektrum.
Vielleicht gibt es auch noch eine bessere Version des FIR’s , aber es handelt sich hierbei um einen speziellen Hilbert Trafo FIR, dieser löscht das unerwünschte Seitenband aus.
Dazu ist eben eine 180° Phasenverschiebung der beiden Eingangeignale (dbl_i und dbl_q) notwendig und das ist nicht bei jedem FIR geboten.
Es sei noch zu erwähnen das es sich hierbei um eine von C Portierte Version handelt
Original C Code:
THX Wolfgang Büscher für den C-Code.
Wenn das mit den Hanning Fenster nicht klappt, dann muss wenigstens das knacken beseitigt werden.
MfG Xorg1990
- - - Aktualisiert - - -
Ähm ja wie soll ich sagen das Hanning-Fester Funktioniert nun.
Ich hätte mir gleich mal die Formel auf Wikipedia genauer ansehen sollen.
Nun muss nur nach das lästige knacken verschwinden und ich bin zufrieden.
ich stehe mal wider vor einen Rätsel und zwar erhalte ich ein kein Ton sobald ich auf die Filterkoeffizienten das Hanning Fenster anwende.
Ein 2tes Problem ist das im Ton immer ein kleines knacken zu hören ist, das ist absolut nervig und macht auch dementsprechende Störungen im FFT Spektrum.
Code:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/html">
<head>
<title>HILBERT-Trafo</title>
</head>
<body>
<script type="text/javascript">
var HILBERT_LENGTH = 200; //FIR Hilbert Length
var FILTER_LEN = Math.floor((HILBERT_LENGTH-1)/2);
var HILBERT_ARRAY = new Float64Array(FILTER_LEN);
var jj=0;
HILBERT_ARRAY[jj]=0.0;
for(;jj<=FILTER_LEN; jj++){
var coeff = jj&1 ? 2.0/(jj*Math.PI) : 0.0;
HILBERT_ARRAY[FILTER_LEN+jj] = coeff;
HILBERT_ARRAY[FILTER_LEN-jj] = -coeff;
}
//Hanning window
/*
for(var I=0;I<FILTER_LEN;I++){
HILBERT_ARRAY[I]*=0.5-0.5*Math.cos((2*Math.PI*I)/(I-1));
}
*/
console.log(HILBERT_ARRAY);
window.AudioContext = window.AudioContext || window.webkitAudioContext;
var context = new AudioContext();
//Globals
var sourceRate = context.sampleRate;
var OscData = new Float32Array(16384);
var NCO_I = new Float32Array(sourceRate);
var NCO_Q = new Float32Array(sourceRate);
var DelayQueue = new Float32Array(FILTER_LEN);
var BufferQueue = new Float32Array(FILTER_LEN);
var queueIndex =0, iWrite =0, iRead=0, n=0, y=null, dbl_i=null, out=null, dbl_q=null, mixed=0, queue_ptr=0, iDelayIndex=0;
var NCO_Freq=500;//NCO Mix Freq.
for (var i = 0; i < sourceRate; i++) {
NCO_I[i] = Math.sin(Math.PI * 2 / sourceRate * i * NCO_Freq) / 4;
NCO_Q[i] = Math.cos(Math.PI * 2 / sourceRate * i * NCO_Freq) / 4;
}
function mix(ev){
var outputLeft = ev.outputBuffer.getChannelData(0);
var outputRight = ev.outputBuffer.getChannelData(1);
var bufferLength = ev.outputBuffer.length;
for(ev=0;ev<bufferLength;ev++,queueIndex++){
//mix dbl_i & dbl_q
dbl_i = OscData[ev]*NCO_I[queueIndex];
dbl_q = OscData[ev]*NCO_Q[queueIndex];
sourceRate<=queueIndex&&(queueIndex-=sourceRate);
if((iDelayIndex>=FILTER_LEN))iDelayIndex=0;
y=DelayQueue[iDelayIndex];
DelayQueue[iDelayIndex++]=dbl_i;//<- DelayLine input
dbl_i=y;
queue_ptr = (queue_ptr + 1) % FILTER_LEN;
BufferQueue[queue_ptr]=dbl_q;//<- Hilbert trafo input
n = queue_ptr;
out = 0.0;
for(var i=FILTER_LEN,coeff_ptr=0;i>=0;i--,coeff_ptr++){
out+= HILBERT_ARRAY[coeff_ptr++] * BufferQueue[n--];
if(n<0)n+=FILTER_LEN;
if(coeff_ptr>=FILTER_LEN-1)coeff_ptr=0;
}
dbl_q=out;
outputLeft[ev] = dbl_i+dbl_q;
//outputRight[ev] = y;
}
}
function OscGetData(ev){
var bufferLength = ev.inputBuffer.length;
var input = ev.inputBuffer.getChannelData(0);
for(var i=0;i<bufferLength;i++){
OscData[i]=input[i];
}
}
var Mixer = context.createScriptProcessor(2048, 0, 2);
var oscGetData = context.createScriptProcessor(2048, 1, 1);
Mixer.onaudioprocess = mix;
oscGetData.onaudioprocess = OscGetData;
//soll ein Soundkartensignal darstellen
var oscillator = context.createOscillator();
oscillator.frequency.value = 1200;
oscillator.type = 0;
oscillator.connect(oscGetData);
oscGetData.connect(context.destination);
Mixer.connect(context.destination);
oscillator.start(0);
</script>
</body>
</html>
Dazu ist eben eine 180° Phasenverschiebung der beiden Eingangeignale (dbl_i und dbl_q) notwendig und das ist nicht bei jedem FIR geboten.
Es sei noch zu erwähnen das es sich hierbei um eine von C Portierte Version handelt
Original C Code:
Code:
{ // Optimized mixer for "downconversion".
// Based on a schematic diagram from the ARRL handbook 1996,
// page 17.73: "The R2: An image-rejecting D-C Receiver"
// Principle: Splitter, TWO Mixers (with I and Q output),
// audio phase shift network, summer, filter.
// Note: 90° phase shifting is done AFTER mixing (in contrast to the
// schemes CFG_FREQ_MIX_LSB_UP and CFG_FREQ_MIX_USB_UP.
for(sample_i=0; sample_i<number_of_samples; ++sample_i)
{
// Let the NCO (numerical controlled oscillator) produce quadrature-phase signals :
dblNcoPhase += dblPhzInc;
while(dblNcoPhase >=(T_Float)SOUND_COS_TABLE_LEN) // "while", not "if" !!
dblNcoPhase -=(T_Float)SOUND_COS_TABLE_LEN; // table index wrap
iCosTableIndex = (int)dblNcoPhase;
dblNcoI = SoundTab_fltCosTable[iCosTableIndex];
dblNcoQ = SoundTab_fltCosTable[(iCosTableIndex+iSineTableOffset) % SOUND_COS_TABLE_LEN];
// Now mix the incoming (higher-frequency) signal ..input_samples[]..
// with a sine and a cosine signal from the NCO ("LO").
dbl_i = input_samples[sample_i]; // this is the INPUT signal
if(pcnv->iMixerScheme == CFG_FREQ_MIX_LSB_DOWNCONVERTER)
{
dbl_q = dbl_i * dblNcoI; // LSB (below NCO freq) moved DOWN
dbl_i = dbl_i * dblNcoQ;
}
else // the "other" sideband with reversed oscillator phases:
{
dbl_q = dbl_i * dblNcoQ; // USB (above NCO freq) moved DOWN
dbl_i = dbl_i * dblNcoI;
}
// arrived here: dbl_i is the output of the "I"-mixer,
// dbl_q is the output of the "Q"-mixer.
// Let the I-channel run through a delay line [ length (N-1)/2 ]
// to compensate the delay from the hilbert trafo (see below).
if( (pcnv->iDelayQIndex < 0)
||(pcnv->iDelayQIndex >= ((SOUND_Hilbert_filter_length-1)/2)) )
pcnv->iDelayQIndex = 0;
y = pcnv->dblDelayQueue[pcnv->iDelayQIndex];
pcnv->dblDelayQueue[pcnv->iDelayQIndex++] = dbl_i;
dbl_i = y;
// Let the Q-channel run through a broadband 90° phase shifter
// (hilbert transformer, implemented as FIR filter here).
// keep the circular buffer pointer 'valid' all the time :
input_queue_end = &pcnv->dblHilbertQueue[SOUND_Hilbert_filter_length-1];
if( (pcnv->pdblHilbertQPointer < &pcnv->dblHilbertQueue[0])
||(pcnv->pdblHilbertQPointer > input_queue_end) )
pcnv->pdblHilbertQPointer = &pcnv->dblHilbertQueue[0];
if( --pcnv->pdblHilbertQPointer < &pcnv->dblHilbertQueue[0] )
pcnv->pdblHilbertQPointer = input_queue_end; // deal with wraparound
*pcnv->pdblHilbertQPointer = dbl_q; // hilbert trafo input
queue_ptr = pcnv->pdblHilbertQPointer; // pointer to read from input queue
coeff_ptr = &SOUND_HilbertCoeffs[0]; // pointer to read from coeff table
y = 0.0; // clear the 'global adder'
j = (SOUND_Hilbert_filter_length+1)/2 -1; // j=12 for 25th-order filter
while( j-- ) // do the MAC's (with every 2nd coeff ZERO)
{
// coeffs[0], [2], [4].. are (almost) zero and are not calculated
// so just skip the 'queue' pointer
++queue_ptr; ++coeff_ptr;
if( queue_ptr > input_queue_end ) // deal with wraparound
queue_ptr = &pcnv->dblHilbertQueue[0];
// odd coefficients, non-zero, do a MAC-operation :
y += ( (*queue_ptr++) * (*coeff_ptr++) );
if( queue_ptr > input_queue_end ) // deal with wraparound
queue_ptr = &pcnv->dblHilbertQueue[0];
}
dbl_q = y; // filter output = sum from all 'taps'
// finally add the output of the "audio phase-shift network"...
output_samples[sample_i] = dbl_i + dbl_q;
} // end for (sample_i ... )
// Generate the coefficients for the Hilber transformer (broadband 90° phase shifter)
n = UConfig.freq_mixer_hilbert_length;
if(n<9)
n=9; // added 2002-12-15
n |= 0x0001; // ensure ODD filter length, but why must bit1 be CLEARED ?
n &= ~0x0002;
if(n > SOUND_HILBERT_MAX_LENGTH)
n = SOUND_HILBERT_MAX_LENGTH; // limit the order of the Hilbert trafo
SOUND_Hilbert_filter_length = n;
/* store the n (odd) length Hilbert Transformer coefficients */
/* in array SOUND_HilbertCoeffs[] */
m = (n - 1) / 2;
SOUND_HilbertCoeffs[m] = 0.0;
for(i = 1; i <= m; i ++)
{
f = i & 1 ? 2.0/(i * pi) : 0.0;
SOUND_HilbertCoeffs[m+i] = f;
SOUND_HilbertCoeffs[m-i] = -f;
}
// apply a Hanning window to the hilbert coeffs to reduce ringing
for(i = 0; i < n; i ++)
SOUND_HilbertCoeffs[i] *= (.5 - .5*cos( (2*pi*i)/(n-1) ));
Wenn das mit den Hanning Fenster nicht klappt, dann muss wenigstens das knacken beseitigt werden.
MfG Xorg1990
- - - Aktualisiert - - -
Ähm ja wie soll ich sagen das Hanning-Fester Funktioniert nun.
Code:
//Hanning window
for(var I=0;I<FILTER_LEN;I++){
HILBERT_ARRAY[I]*=0.5-0.5*Math.cos(2*Math.PI*I/FILTER_LEN-1);
}
Ich hätte mir gleich mal die Formel auf Wikipedia genauer ansehen sollen.

Nun muss nur nach das lästige knacken verschwinden und ich bin zufrieden.