add input monitor
This commit is contained in:
parent
e68cf07694
commit
875650345b
@ -19,6 +19,9 @@ class DDS {
|
||||
phase += ftw; // wraps on overflow
|
||||
return sin(phase*2.0*M_PI/(double)PHASE_MAX);
|
||||
}
|
||||
phase_t get_phase() {
|
||||
return phase;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, unsigned int order>
|
||||
@ -60,4 +63,7 @@ class Lockin {
|
||||
phase -= ftw; // wraps on underflow
|
||||
return lpf.update(rotated);
|
||||
}
|
||||
phase_t get_phase() {
|
||||
return phase;
|
||||
}
|
||||
};
|
||||
|
120
sndlock.cpp
120
sndlock.cpp
@ -23,17 +23,26 @@
|
||||
#define SND_BUFLEN 4096
|
||||
|
||||
static std::atomic<bool> shutdown_threads;
|
||||
|
||||
static std::atomic<double> frequency[SND_PCHAN];
|
||||
static std::atomic<double> amplitude[SND_PCHAN];
|
||||
|
||||
#define HIST_DEPTH 512
|
||||
|
||||
static std::atomic<double> peak;
|
||||
static std::atomic<bool> clipped;
|
||||
static std::atomic<int> in_wave_trigger;
|
||||
static std::mutex in_wave_mutex;
|
||||
static float in_wave[HIST_DEPTH];
|
||||
|
||||
static std::atomic<double> lpf_bandwidth[SND_PCHAN];
|
||||
static std::mutex li_hist_mutex;
|
||||
static std::atomic<bool> li_hist_pause[SND_PCHAN];
|
||||
static float li_hist_mag[SND_PCHAN][HIST_DEPTH];
|
||||
static float li_hist_phase[SND_PCHAN][HIST_DEPTH];
|
||||
|
||||
enum class InWaveState { delay, wait_trigger, capturing };
|
||||
|
||||
static void dsp_thread()
|
||||
{
|
||||
struct sio_hdl *hdl;
|
||||
@ -78,6 +87,14 @@ static void dsp_thread()
|
||||
|
||||
FIFO<phase_t, 8> ftw_fifo[SND_PCHAN];
|
||||
|
||||
int clipped_count = 0;
|
||||
double peak_running = 0.0;
|
||||
int peak_count = 0;
|
||||
phase_t last_trig_phase = 0;
|
||||
InWaveState in_wave_state = InWaveState::delay;
|
||||
int in_wave_count = 0;
|
||||
float in_wave_buf[HIST_DEPTH];
|
||||
|
||||
Lockin<4> lockin[SND_PCHAN];
|
||||
for(int i=0;i<SND_PCHAN;i++)
|
||||
// input channels are averaged together to reduce uncorrelated noise
|
||||
@ -126,25 +143,75 @@ static void dsp_thread()
|
||||
}
|
||||
buf_in_offset -= sizeof(buf_in);
|
||||
}
|
||||
for(int i=0;i<SND_PCHAN;i++)
|
||||
for(int j=0;j<read/(SND_RCHAN*sizeof(buf_in[0]));j++) {
|
||||
double sample = 0.0;
|
||||
for(int k=0;k<SND_RCHAN;k++)
|
||||
sample += (double)buf_in[SND_RCHAN*j+k];
|
||||
std::complex<double> lockin_out = lockin[i].update(sample);
|
||||
for(int i=0;i<read/(SND_RCHAN*sizeof(buf_in[0]));i++) {
|
||||
double sample = 0.0;
|
||||
for(int j=0;j<SND_RCHAN;j++) {
|
||||
double sample_d = (double)buf_in[SND_RCHAN*i+j];
|
||||
sample += sample_d;
|
||||
if(std::abs(sample_d) > 0.99*pow(2.0, SND_BITS-1))
|
||||
// display the clipped indicator for about one second
|
||||
clipped_count = SND_RATE;
|
||||
}
|
||||
if(clipped_count > 0) {
|
||||
clipped_count--;
|
||||
clipped = true;
|
||||
} else
|
||||
clipped = false;
|
||||
|
||||
if(!li_hist_pause[i]) {
|
||||
li_count[i]++;
|
||||
if(li_count[i] == 200) {
|
||||
li_count[i] = 0;
|
||||
double sample_abs = std::abs(sample);
|
||||
if(sample_abs > peak_running)
|
||||
peak_running = sample_abs;
|
||||
peak_count++;
|
||||
if(peak_count == SND_RATE/10) {
|
||||
peak_count = 0;
|
||||
peak = peak_running/(pow(2.0, SND_BITS-1)*SND_RCHAN);
|
||||
peak_running = 0.0;
|
||||
}
|
||||
|
||||
phase_t trig_phase = lockin[in_wave_trigger].get_phase();
|
||||
bool trigger = trig_phase > last_trig_phase;
|
||||
last_trig_phase = trig_phase;
|
||||
switch(in_wave_state) {
|
||||
case InWaveState::delay:
|
||||
in_wave_count++;
|
||||
if(in_wave_count == SND_RATE/10)
|
||||
in_wave_state = InWaveState::wait_trigger;
|
||||
break;
|
||||
case InWaveState::wait_trigger:
|
||||
if(trigger) {
|
||||
in_wave_count = 0;
|
||||
in_wave_state = InWaveState::capturing;
|
||||
}
|
||||
break;
|
||||
case InWaveState::capturing:
|
||||
in_wave_buf[in_wave_count++] = sample/(pow(2.0, SND_BITS-1)*SND_RCHAN);
|
||||
if(in_wave_count == HIST_DEPTH) {
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(in_wave_mutex);
|
||||
std::memcpy(in_wave, in_wave_buf, sizeof(in_wave));
|
||||
}
|
||||
in_wave_count = 0;
|
||||
in_wave_state = InWaveState::delay;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
for(int j=0;j<SND_PCHAN;j++) {
|
||||
std::complex<double> lockin_out = lockin[j].update(sample);
|
||||
|
||||
if(!li_hist_pause[j]) {
|
||||
li_count[j]++;
|
||||
if(li_count[j] == 200) {
|
||||
li_count[j] = 0;
|
||||
std::lock_guard<std::mutex> guard(li_hist_mutex);
|
||||
std::memmove(&li_hist_mag[i][0], &li_hist_mag[i][1], (HIST_DEPTH-1)*sizeof(float));
|
||||
li_hist_mag[i][HIST_DEPTH-1] = std::abs(lockin_out);
|
||||
std::memmove(&li_hist_phase[i][0], &li_hist_phase[i][1], (HIST_DEPTH-1)*sizeof(float));
|
||||
li_hist_phase[i][HIST_DEPTH-1] = std::arg(lockin_out);
|
||||
std::memmove(&li_hist_mag[j][0], &li_hist_mag[j][1], (HIST_DEPTH-1)*sizeof(float));
|
||||
li_hist_mag[j][HIST_DEPTH-1] = std::abs(lockin_out);
|
||||
std::memmove(&li_hist_phase[j][0], &li_hist_phase[j][1], (HIST_DEPTH-1)*sizeof(float));
|
||||
li_hist_phase[j][HIST_DEPTH-1] = std::arg(lockin_out);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(sio_eof(hdl)) {
|
||||
@ -243,6 +310,31 @@ int main(int argc, char* argv[])
|
||||
amplitude[i] = amplitude_l;
|
||||
}
|
||||
}
|
||||
if(ImGui::CollapsingHeader("Input monitor")) {
|
||||
ImGui::AlignTextToFramePadding();
|
||||
ImGui::Text("level:");
|
||||
ImGui::SameLine();
|
||||
ImGui::ProgressBar((float)peak, ImVec2(30.0f*ImGui::GetFontSize(), 0.0f));
|
||||
if(clipped) {
|
||||
ImGui::SameLine();
|
||||
ImGui::TextColored(ImVec4(1.0f, 0.0f, 0.0f, 1.0f), "clipped!");
|
||||
}
|
||||
ImGui::AlignTextToFramePadding();
|
||||
ImGui::Text("trigger:");
|
||||
ImGui::SameLine();
|
||||
int in_wave_trigger_l = in_wave_trigger;
|
||||
char str[64];
|
||||
for(int i=0;i<SND_PCHAN;i++) {
|
||||
sprintf(str, "ch%d", i);
|
||||
ImGui::RadioButton(str, &in_wave_trigger_l, i);
|
||||
if(i < (SND_PCHAN-1)) ImGui::SameLine();
|
||||
}
|
||||
in_wave_trigger = in_wave_trigger_l;
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(in_wave_mutex);
|
||||
ImGui::PlotLines("waveform", in_wave, HIST_DEPTH, 0, 0, -1.0f, 1.0f, ImVec2(0.0f, 200.0f));
|
||||
}
|
||||
}
|
||||
if(ImGui::CollapsingHeader("Demodulation", ImGuiTreeNodeFlags_DefaultOpen)) {
|
||||
for(int i=0;i<SND_PCHAN;i++) {
|
||||
char str[64];
|
||||
|
Loading…
Reference in New Issue
Block a user