mirror of
https://github.com/radio95-rnt/rds95.git
synced 2026-02-27 12:53:53 +01:00
make it modulate a sine wave which is generated live, not sure if works
This commit is contained in:
69
gen_wave.py
69
gen_wave.py
@@ -1,69 +0,0 @@
|
|||||||
PLOT = False
|
|
||||||
FFT = PLOT and False
|
|
||||||
|
|
||||||
import math
|
|
||||||
import io, os
|
|
||||||
if PLOT: import matplotlib.pyplot as plt
|
|
||||||
if FFT: import numpy as np
|
|
||||||
|
|
||||||
DATA_RATE = 1187.5
|
|
||||||
|
|
||||||
ratio = 4
|
|
||||||
sample_rate = DATA_RATE*ratio
|
|
||||||
print(f"{sample_rate=}")
|
|
||||||
if not sample_rate.is_integer(): raise ValueError("Need a even value")
|
|
||||||
|
|
||||||
PATH = os.path.dirname(os.path.abspath(__file__))
|
|
||||||
|
|
||||||
outc = io.open(f"{PATH}/src/waveforms.c", mode="w", encoding="utf8")
|
|
||||||
outh = io.open(f"{PATH}/src/waveforms.h", mode="w", encoding="utf8")
|
|
||||||
|
|
||||||
header = u"""
|
|
||||||
/* This file was automatically generated by "gen_wave.py".
|
|
||||||
(C) 2014 Christophe Jacquet.
|
|
||||||
(C) 2023 Anthony96922.
|
|
||||||
(C) 2025 kuba201.
|
|
||||||
Released under the GNU GPL v3 license.
|
|
||||||
*/
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
outc.write(header)
|
|
||||||
outh.write(header)
|
|
||||||
|
|
||||||
def generate():
|
|
||||||
t = [i / sample_rate for i in range(ratio)]
|
|
||||||
out = [math.sin(2 * math.pi * DATA_RATE * time) for time in t]
|
|
||||||
print(f"{len(out)=}")
|
|
||||||
|
|
||||||
if PLOT:
|
|
||||||
plt.plot(out*4, label="out")
|
|
||||||
plt.legend()
|
|
||||||
plt.axvline(x=len(out)*2, color='r', linestyle='--', label='center')
|
|
||||||
plt.grid(True)
|
|
||||||
plt.show()
|
|
||||||
|
|
||||||
if FFT:
|
|
||||||
N = len(out)
|
|
||||||
fft_out = np.fft.fft(out)
|
|
||||||
fft_freqs = np.fft.fftfreq(N, d=1/sample_rate)
|
|
||||||
|
|
||||||
plt.figure(figsize=(10, 6))
|
|
||||||
plt.plot(fft_freqs[:N//2], np.abs(fft_out)[:N//2])
|
|
||||||
plt.xlim(0,DATA_RATE*2.5)
|
|
||||||
plt.title("FFT of the waveform")
|
|
||||||
plt.xlabel("Frequency (Hz)")
|
|
||||||
plt.ylabel("Magnitude")
|
|
||||||
plt.grid(True)
|
|
||||||
plt.show()
|
|
||||||
|
|
||||||
outc.write(u"float waveform_biphase[{size}] = {{{values}}};\n\n".format(
|
|
||||||
values = u", ".join(map(str, out)),
|
|
||||||
size = len(out)))
|
|
||||||
|
|
||||||
outh.write(u"extern float waveform_biphase[{size}];\n".format(size=len(out)))
|
|
||||||
|
|
||||||
generate()
|
|
||||||
|
|
||||||
outc.close()
|
|
||||||
outh.close()
|
|
||||||
@@ -1,7 +1,5 @@
|
|||||||
#include "modulator.h"
|
#include "modulator.h"
|
||||||
|
|
||||||
static float waveform[2][FILTER_SIZE];
|
|
||||||
|
|
||||||
void Modulator_saveToFile(RDSModulatorParameters *emp, const char *option) {
|
void Modulator_saveToFile(RDSModulatorParameters *emp, const char *option) {
|
||||||
char modulatorPath[128];
|
char modulatorPath[128];
|
||||||
snprintf(modulatorPath, sizeof(modulatorPath), "%s/.rdsModulator", getenv("HOME"));
|
snprintf(modulatorPath, sizeof(modulatorPath), "%s/.rdsModulator", getenv("HOME"));
|
||||||
@@ -90,14 +88,7 @@ void init_rds_modulator(RDSModulator* rdsMod, RDSEncoder* enc) {
|
|||||||
|
|
||||||
rdsMod->enc = enc;
|
rdsMod->enc = enc;
|
||||||
|
|
||||||
if(STREAMS > 0) rdsMod->data[1].symbol_shifting.symbol_shift = FILTER_SIZE / 2;
|
if(STREAMS > 0) rdsMod->data[1].symbol_shift = FILTER_SIZE / 2;
|
||||||
|
|
||||||
for (uint8_t i = 0; i < 2; i++) {
|
|
||||||
for (uint16_t j = 0; j < FILTER_SIZE; j++) {
|
|
||||||
waveform[i][j] = i ?
|
|
||||||
+waveform_biphase[j] : -waveform_biphase[j];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(modulatorsaved()) {
|
if(modulatorsaved()) {
|
||||||
Modulator_loadFromFile(&rdsMod->params);
|
Modulator_loadFromFile(&rdsMod->params);
|
||||||
@@ -107,8 +98,10 @@ void init_rds_modulator(RDSModulator* rdsMod, RDSEncoder* enc) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
float get_rds_sample(RDSModulator* rdsMod, uint8_t stream) {
|
float get_rds_sample(RDSModulator* rdsMod, uint8_t stream) {
|
||||||
float *cur_waveform;
|
rdsMod->data[stream].phase += 1187.5 / RDS_SAMPLE_RATE;
|
||||||
if (rdsMod->data[stream].sample_count == FILTER_SIZE) {
|
|
||||||
|
if (rdsMod->data[stream].phase >= 1.0f) {
|
||||||
|
rdsMod->data[stream].phase -= 1.0f;
|
||||||
if (rdsMod->data[stream].bit_pos == BITS_PER_GROUP) {
|
if (rdsMod->data[stream].bit_pos == BITS_PER_GROUP) {
|
||||||
get_rds_bits(rdsMod->enc, rdsMod->data[stream].bit_buffer, stream);
|
get_rds_bits(rdsMod->enc, rdsMod->data[stream].bit_buffer, stream);
|
||||||
rdsMod->data[stream].bit_pos = 0;
|
rdsMod->data[stream].bit_pos = 0;
|
||||||
@@ -117,33 +110,10 @@ float get_rds_sample(RDSModulator* rdsMod, uint8_t stream) {
|
|||||||
rdsMod->data[stream].cur_bit = rdsMod->data[stream].bit_buffer[rdsMod->data[stream].bit_pos++];
|
rdsMod->data[stream].cur_bit = rdsMod->data[stream].bit_buffer[rdsMod->data[stream].bit_pos++];
|
||||||
rdsMod->data[stream].prev_output = rdsMod->data[stream].cur_output;
|
rdsMod->data[stream].prev_output = rdsMod->data[stream].cur_output;
|
||||||
rdsMod->data[stream].cur_output = rdsMod->data[stream].prev_output ^ rdsMod->data[stream].cur_bit;
|
rdsMod->data[stream].cur_output = rdsMod->data[stream].prev_output ^ rdsMod->data[stream].cur_bit;
|
||||||
|
|
||||||
uint16_t idx = rdsMod->data[stream].in_sample_index;
|
|
||||||
cur_waveform = waveform[rdsMod->data[stream].cur_output];
|
|
||||||
|
|
||||||
for (uint16_t i = 0; i < FILTER_SIZE; i++) {
|
|
||||||
rdsMod->data[stream].sample_buffer[idx++] += *cur_waveform++;
|
|
||||||
if (idx == SAMPLE_BUFFER_SIZE) idx = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
rdsMod->data[stream].in_sample_index += FILTER_SIZE;
|
|
||||||
if (rdsMod->data[stream].in_sample_index == SAMPLE_BUFFER_SIZE) rdsMod->data[stream].in_sample_index = 0;
|
|
||||||
|
|
||||||
rdsMod->data[stream].sample_count = 0;
|
|
||||||
}
|
|
||||||
rdsMod->data[stream].sample_count++;
|
|
||||||
|
|
||||||
float sample = rdsMod->data[stream].sample_buffer[rdsMod->data[stream].out_sample_index];
|
|
||||||
if(stream != 0 && rdsMod->data[stream].symbol_shifting.symbol_shift != 0) {
|
|
||||||
rdsMod->data[stream].symbol_shifting.sample_buffer[rdsMod->data[stream].symbol_shifting.sample_buffer_idx++] = rdsMod->data[stream].sample_buffer[rdsMod->data[stream].out_sample_index];
|
|
||||||
|
|
||||||
if (rdsMod->data[stream].symbol_shifting.sample_buffer_idx == rdsMod->data[stream].symbol_shifting.symbol_shift) rdsMod->data[stream].symbol_shifting.sample_buffer_idx = 0;
|
|
||||||
|
|
||||||
sample = rdsMod->data[stream].symbol_shifting.sample_buffer[rdsMod->data[stream].symbol_shifting.sample_buffer_idx];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rdsMod->data[stream].sample_buffer[rdsMod->data[stream].out_sample_index++] = 0;
|
float sample = sinf(M_2PI * (rdsMod->data[stream].phase - rdsMod->data[stream].symbol_shift));
|
||||||
if (rdsMod->data[stream].out_sample_index == SAMPLE_BUFFER_SIZE) rdsMod->data[stream].out_sample_index = 0;
|
if(rdsMod->data[stream].cur_output == 0) sample = -sample; // do bpsk
|
||||||
|
|
||||||
uint8_t tooutput = rdsMod->params.rdsgen > stream ? 1 : 0;
|
uint8_t tooutput = rdsMod->params.rdsgen > stream ? 1 : 0;
|
||||||
return sample*rdsMod->params.level*tooutput;
|
return sample*rdsMod->params.level*tooutput;
|
||||||
|
|||||||
@@ -17,25 +17,15 @@ typedef struct
|
|||||||
uint16_t crc;
|
uint16_t crc;
|
||||||
} RDSModulatorParametersFile;
|
} RDSModulatorParametersFile;
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
uint8_t symbol_shift: 7;
|
|
||||||
float sample_buffer[SAMPLE_BUFFER_SIZE];
|
|
||||||
uint8_t sample_buffer_idx : 7;
|
|
||||||
} RDSModulatorSymbolShifting;
|
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
uint8_t bit_buffer[BITS_PER_GROUP];
|
uint8_t bit_buffer[BITS_PER_GROUP];
|
||||||
uint8_t bit_pos : 7;
|
uint8_t bit_pos : 7;
|
||||||
float sample_buffer[SAMPLE_BUFFER_SIZE];
|
|
||||||
uint8_t prev_output : 1;
|
uint8_t prev_output : 1;
|
||||||
uint8_t cur_output : 1;
|
uint8_t cur_output : 1;
|
||||||
uint8_t cur_bit : 1;
|
uint8_t cur_bit : 1;
|
||||||
uint8_t sample_count;
|
uint8_t symbol_shift: 7;
|
||||||
uint16_t in_sample_index;
|
float phase;
|
||||||
uint16_t out_sample_index;
|
|
||||||
RDSModulatorSymbolShifting symbol_shifting;
|
|
||||||
} RDSModulatorModulationData;
|
} RDSModulatorModulationData;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|||||||
@@ -11,8 +11,6 @@
|
|||||||
#define GROUP_LENGTH 4
|
#define GROUP_LENGTH 4
|
||||||
#define BITS_PER_GROUP (GROUP_LENGTH * (BLOCK_SIZE + POLY_DEG))
|
#define BITS_PER_GROUP (GROUP_LENGTH * (BLOCK_SIZE + POLY_DEG))
|
||||||
#define RDS_SAMPLE_RATE 4750
|
#define RDS_SAMPLE_RATE 4750
|
||||||
#define FILTER_SIZE 4
|
|
||||||
#define SAMPLE_BUFFER_SIZE (FILTER_SIZE*2)
|
|
||||||
|
|
||||||
#define STREAMS 2
|
#define STREAMS 2
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
|
|
||||||
/* This file was automatically generated by "gen_wave.py".
|
|
||||||
(C) 2014 Christophe Jacquet.
|
|
||||||
(C) 2023 Anthony96922.
|
|
||||||
(C) 2025 kuba201.
|
|
||||||
Released under the GNU GPL v3 license.
|
|
||||||
*/
|
|
||||||
|
|
||||||
float waveform_biphase[4] = {0.0, 1.0, 1.2246467991473532e-16, -1.0};
|
|
||||||
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
|
|
||||||
/* This file was automatically generated by "gen_wave.py".
|
|
||||||
(C) 2014 Christophe Jacquet.
|
|
||||||
(C) 2023 Anthony96922.
|
|
||||||
(C) 2025 kuba201.
|
|
||||||
Released under the GNU GPL v3 license.
|
|
||||||
*/
|
|
||||||
|
|
||||||
extern float waveform_biphase[4];
|
|
||||||
Reference in New Issue
Block a user