diff options
Diffstat (limited to 'tools')
-rw-r--r-- | tools/pdm2pcm.py | 74 |
1 files changed, 66 insertions, 8 deletions
diff --git a/tools/pdm2pcm.py b/tools/pdm2pcm.py index f21803a..765c8b6 100644 --- a/tools/pdm2pcm.py +++ b/tools/pdm2pcm.py @@ -13,13 +13,68 @@ def load_pdm_file(filename): pdm_signal = bit_data return pdm_signal -def pdm_to_pcm(pdm_signal, decimation_factor=64): - # Design a low-pass filter - fir_filter = firwin(numtaps=101, cutoff=0.5/decimation_factor) - # Filter the PDM signal - filtered = lfilter(fir_filter, [1.0], pdm_signal) - # Decimate (downsample) - pcm_signal = filtered[::decimation_factor] + +def cic_decimate(input_signal, decimation_factor=64, stages=3, delay=1): + R = decimation_factor + N = stages + M = delay + + # Integrator stages + integrators = [0] * N + integrator_outputs = [] + + for sample in input_signal: + integrators[0] += sample + for i in range(1, N): + integrators[i] += integrators[i-1] + integrator_outputs.append(integrators[-1]) + + # Decimation + decimated = integrator_outputs[R-1::R] + + # Comb stages + combs = [0] * N + comb_outputs = [] + delays = [[0]*M for _ in range(N)] + + for sample in decimated: + diff = sample + for i in range(N): + delayed = delays[i].pop(0) + delays[i].append(diff) + diff = diff - delayed + combs[i] = diff + comb_outputs.append(combs[-1]) + + return comb_outputs + + +def pdm_to_pcm(pdm_signal, decimation_factor=64, filter_type='fir', filter_kwargs={}): + if filter_type == 'fir': + # Design a low-pass filter + defaults = dict(numtaps=501, cutoff=0.5/decimation_factor) + kwargs = {} + kwargs.update(defaults) + kwargs.update(filter_kwargs) + fir_filter = firwin(**kwargs) + # Filter the PDM signal + filtered = lfilter(fir_filter, [1.0], pdm_signal) + # Decimate (downsample) + pcm_signal = filtered[::decimation_factor] + + elif filter_type == 'cic': + # Use CIC filter + defaults = dict(stages=3, delay=1) + kwargs = {} + kwargs.update(defaults) + kwargs.update(filter_kwargs) + # Convert 1-bit PDM to +/-1 format + print(pdm_signal) + pdm_signal = pdm_signal.astype(int) + #pdm_signal = [2*s - 1 for s in pdm_signal.astype(int)] + pcm_signal = cic_decimate(pdm_signal, decimation_factor=decimation_factor, **kwargs) + pcm_signal = numpy.array(pcm_signal, dtype=float) + return pcm_signal def parse(): @@ -28,6 +83,7 @@ def parse(): parser = argparse.ArgumentParser(description='Process an input file and write to an output file.') parser.add_argument('-i', '--input', type=str, required=True, help='Path to the input file') parser.add_argument('-o', '--output', type=str, required=True, help='Path to the output file') + parser.add_argument('--filter', type=str, default='fir') parser.add_argument('--samplerate', type=int, default=16000) parser.add_argument('--oversample', type=int, default=64) @@ -41,10 +97,12 @@ def main(): out_path = args.output pdm_data = load_pdm_file(pdm_path) + print('loaded', pdm_data.shape) + # Convert to PCM oversample = args.oversample samplerate = args.samplerate - pcm_data = pdm_to_pcm(pdm_data, decimation_factor=oversample) + pcm_data = pdm_to_pcm(pdm_data, decimation_factor=oversample, filter_type=args.filter) # Normalize and save to WAV pcm_data = np.expand_dims(pcm_data, axis=1) |