Skip to content

Commit 1eaf503

Browse files
Merge pull request #15 from nipunaw/sprint-3
Compiling software changes from Sprint 3
2 parents 3c55481 + 1ca3f07 commit 1eaf503

23 files changed

+1754
-901
lines changed

README.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,21 +30,21 @@ The HDL is synthesized by the Vivado 2021.1 build system. It has not been tested
3030
3. Double click on "Generate Bitstream" to generate the bitstream for the Arty A7-35 (xc7a35ticsg324-1L) FPGA, which is preconfigured. Other devices may be selected, however neither performance nor compatibility are guaranteed.
3131

3232
The default pinout, which can also be found in the constraint file, is:
33-
clk - E3
34-
rst - C2
35-
sampleIn[0:7] - D4, D3, F4, F3, E2, D2, H2, G2
36-
sampleOut[0:7] - G13, B11, A11, D12, D13, B18, A18, K16
33+
- clk - E3
34+
- rst - C2
35+
- sampleIn[0:7] - D4, D3, F4, F3, E2, D2, H2, G2
36+
- sampleOut[0:7] - G13, B11, A11, D12, D13, B18, A18, K16
3737

3838
For status of the filter on the Arty A7 devboard, it outputs to a status LED:
39-
filterActive - H5
39+
- filterActive - H5
4040

4141
The switch on the devboard enables the filter
42-
filterEn - A8
42+
- filterEn - A8
4343

4444

4545
The pins for the TLC0820:
46-
extCS - E15
47-
extRD - E16
48-
extReady - D15
46+
- extCS - E15
47+
- extRD - E16
48+
- extReady - D15
4949

5050
The MX7224 is held in transparent mode

package-lock.json

Lines changed: 1309 additions & 758 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,27 @@
66
"dependencies": {
77
"@joe_six/duarte-watanabe-peak-detection": "^0.2.0",
88
"@joe_six/smoothed-z-score-peak-signal-detection": "^0.1.2",
9+
"@reduxjs/toolkit": "^1.7.2",
910
"@testing-library/jest-dom": "^5.11.4",
1011
"@testing-library/react": "^11.1.0",
1112
"@testing-library/user-event": "^12.1.10",
1213
"@types/jest": "^27.4.0",
1314
"@types/node": "^17.0.10",
1415
"@types/react": "^17.0.38",
16+
"@types/react-redux": "^7.1.22",
1517
"bootstrap": "^5.1.3",
18+
"decibels": "^2.0.0",
1619
"fft-js": "^0.0.12",
1720
"fft-windowing": "^0.1.4",
1821
"fili": "^2.0.3",
22+
"fourier-transform": "^1.1.2",
1923
"nodeplotlib": "^1.0.0",
2024
"pitchfinder": "^2.3.2",
2125
"python-shell": "^3.0.1",
2226
"react": "^17.0.2",
2327
"react-bootstrap": "^2.0.3",
2428
"react-dom": "^17.0.2",
29+
"react-redux": "^7.2.6",
2530
"typescript": "^4.5.4",
2631
"wav-decoder": "^1.3.0",
2732
"web-vitals": "^1.0.1"
@@ -66,6 +71,7 @@
6671
"@types/react-dom": "^17.0.11",
6772
"electron": "^16.0.7",
6873
"electron-builder": "^22.14.5",
74+
"electron-devtools-installer": "^3.2.0",
6975
"react-scripts": "^4.0.3"
7076
},
7177
"build": {

public/main.js

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
// Generics
1+
const {
2+
default: installExtension,
3+
REDUX_DEVTOOLS,
4+
} = require("electron-devtools-installer");
25
const { app, BrowserWindow, Menu, ipcMain } = require("electron");
36
const fs = require("fs");
47
const { resolve } = require("path");
@@ -17,7 +20,7 @@ function createWindow() {
1720
},
1821
});
1922

20-
//load the index.html from a url
23+
// Load the index.html from a url
2124
win.loadURL("http://localhost:3000");
2225

2326
// Open the DevTools.
@@ -60,24 +63,24 @@ function createWindow() {
6063
}
6164
);
6265

63-
64-
ipcMain.on("process-audio", (event, rawRecordedData, sampleRate) => {
65-
//Pitch method is deprecated
66+
ipcMain.on("process-audio", (event, rawRecordedData, sampleRate, fftData) => {
6667
try {
67-
const pitch = GetPitchValue(rawRecordedData);
68-
const noiseTaps = fftAnalysis(rawRecordedData, sampleRate);
68+
//Pitch method is deprecated
69+
//const pitch = GetPitchValue(rawRecordedData);
70+
const noiseTaps = fftAnalysis(rawRecordedData, sampleRate, fftData);
6971

7072
win.webContents.send(
7173
"audio-finished",
7274
true,
73-
`Sent information over UART if connected`,
75+
`No errors occured while processing!`,
7476
noiseTaps
7577
);
76-
} catch {
78+
} catch (e) {
79+
console.log(e);
7780
win.webContents.send(
7881
"audio-finished",
7982
false,
80-
`An error has occured.`,
83+
`An error has occured while processing.`,
8184
[]
8285
);
8386
}
@@ -99,10 +102,12 @@ function readFile(filepath, mimeType) {
99102
});
100103
}
101104

102-
// This method will be called when Electron has finished
103-
// initialization and is ready to create browser windows.
104-
// Some APIs can only be used after this event occurs.
105-
app.whenReady().then(createWindow);
105+
app.whenReady().then(() => {
106+
installExtension(REDUX_DEVTOOLS)
107+
.then((name) => console.log(`Added Extension: ${name}`))
108+
.catch((err) => console.log("An error occurred: ", err));
109+
createWindow();
110+
});
106111

107112
// Quit when all windows are closed, except on macOS. There, it's common
108113
// for applications and their menu bar to stay active until the user quits

public/main/audioProcess.js

Lines changed: 85 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -5,32 +5,46 @@ const fft = require('fft-js').fft;
55
const fftUtil = require('fft-js').util;
66
const windowing = require('fft-windowing');
77
const Fili = require('fili');
8+
var ft = require('fourier-transform');
9+
var db = require('decibels');
810
// Smoothing and Plots
911
const smoothed_z_score = require("@joe_six/smoothed-z-score-peak-signal-detection");
1012
const detect_peaks = require("@joe_six/duarte-watanabe-peak-detection")
11-
const { plot, Plot } = require("nodeplotlib");
13+
const { plot, Plot} = require("nodeplotlib");
1214

13-
const fftAnalysis = (rawRecordedData, sampleRate) => {
14-
var windowedRecordedData = windowing.hann(rawRecordedData);
15-
var phasors = fft(windowedRecordedData.slice(0, 262144)); // 48000 > samples
16-
var frequencies = fftUtil.fftFreq(phasors, sampleRate); // Sample rate and coef is just used for length, and frequency step
17-
var magnitudes = fftUtil.fftMag(phasors);
15+
const fftAnalysis = (rawData, sampleRate, fftData) => {
16+
let N = 32768;
17+
let win = windowing.hann(rawData.slice(0, N), N); //rawData.slice(0, N),
18+
let spectrum = fft(win); // 48000 > samples
19+
let frequencies = fftUtil.fftFreq(spectrum, sampleRate); // Sample rate and coef is just used for length, and frequency step
20+
let magnitudes = fftUtil.fftMag(spectrum);
21+
let spectrum2 = ft(rawData.slice(0, N));
22+
let decibels = spectrum2.map((value) => db.fromGain(value))
1823

24+
console.log("##### META-DATA ON FFT-JS #####");
1925
console.log("Sample Rate: " + sampleRate);
20-
console.log("Length of raw data: " + rawRecordedData.length);
21-
console.log("Length of windowed data: " + windowedRecordedData.length);
22-
console.log("Length of phasors: " + phasors.length);
26+
console.log("Length of raw data: " + rawData.length);
27+
console.log("Length of windowed data: " + win.length);
28+
console.log("Length of phasors: " + spectrum.length);
2329
console.log("Length of frequencies: " + frequencies.length);
2430
console.log("Length of magnitudes: " + magnitudes.length);
2531
console.log("");
32+
33+
let fftFreq = new Float32Array(fftData.length);
34+
for (let i = 0; i < fftData.length; i++) {
35+
fftFreq[i] = i*((sampleRate/2)/(fftData.length));
36+
}
37+
38+
graphFrequencySpectrum(fftFreq, fftData, {title: "AnalyserNode Frequency Spectrum"}); //{"logFreq": true}
39+
graphFrequencySpectrum(frequencies, magnitudes, {title: "FFT-JS Frequency Spectrum"}); //{"scaleMagnitude": true, "logFreq": true}
40+
graphFrequencySpectrum(frequencies, decibels, {title: "FFT-ASM Frequency Spectrum"});
2641
return firFilterTaps(frequencies, magnitudes, sampleRate);
2742
}
2843

2944
const firFilterTaps = (frequencies, magnitudes, sampleRate) => {
3045
// TO-DO: Continue testing smoothing methods, for now electing Watanabe method
3146
//const peaksSmoothed = smoothed_z_score(magnitudes, {lag: 40, threshold: 4.5, influence: 0.2});
32-
33-
const noiseTaps = noiseRemoval(frequencies, magnitudes, 101, sampleRate);
47+
const noiseTaps = noiseRemoval(frequencies, magnitudes, 101, sampleRate, 150);
3448
return noiseTaps;
3549
}
3650

@@ -41,25 +55,58 @@ const identifyPeaks = (magnitudes, mpdVal) => {
4155
}
4256

4357
// Helper function for graphing/testing
44-
const graphFrequencies= (frequencies, magnitudes, logScale, plotType) => {
45-
let logFrequencies = [];
46-
if (logScale == true) {
47-
for (let i = 0; i < frequencies.length; i++) {
48-
logFrequencies.push(Math.log10(frequencies[i]));
58+
const graphFrequencySpectrum=(frequencies, magnitudes, params={}) => {
59+
60+
if (frequencies.length != magnitudes.length) {
61+
console.log("Frequency bins length mismatches magnitude length")
62+
return
63+
}
64+
65+
let length = frequencies.length;
66+
let xaxisType = params["logFreq"] || "log";
67+
let scaleMagnitude = params["scaleMagnitude"] || false;
68+
let fftSize = params["fftSize"] || 32768;
69+
let title = params["title"] || "Frequency Spectrum";
70+
let plotType = 'scatter';
71+
72+
let graphFrequencies = new Array(length);
73+
let graphMagnitudes = new Array(length);
74+
75+
76+
for (let i = 0; i < length; i++) {
77+
graphFrequencies[i] = frequencies[i];
78+
}
79+
80+
if (scaleMagnitude == true) {
81+
for (let i = 0; i < length; i++) {
82+
graphMagnitudes[i] = 20*Math.log10(2*magnitudes[i]/fftSize);
4983
}
5084
} else {
51-
logFrequencies = frequencies;
85+
for (let i = 0; i < length; i++) {
86+
graphMagnitudes[i] = magnitudes[i];
87+
}
5288
}
5389

5490
const data = [
5591
{
56-
x: logFrequencies,
57-
y: magnitudes,
92+
x: graphFrequencies,
93+
y: graphMagnitudes,
5894
type: plotType
59-
},
95+
}
6096
];
97+
98+
const layout = {
99+
title: title,
100+
xaxis: {
101+
title: "Frequency [Hz]",
102+
type: xaxisType
103+
},
104+
yaxis: {
105+
title: "Magnitude [dBFS]"
106+
}
107+
};
61108

62-
plot(data);
109+
plot(data, layout);
63110
}
64111

65112
const bandstopTaps = (filterOrder, sampleRate, lowerFreq, upperFreq, attenuation) => {
@@ -74,30 +121,34 @@ const bandstopTaps = (filterOrder, sampleRate, lowerFreq, upperFreq, attenuation
74121
return firFilterCoeffsK;
75122
}
76123

77-
const noiseRemoval = (frequencies, magnitudes, filterOrder, sampleRate) => {
124+
const noiseRemoval = (frequencies, magnitudes, filterOrder, sampleRate, limit) => {
78125
const peaksWatanabeIndices = identifyPeaks(magnitudes, 50);
79-
let noisyFrequencies = [];
126+
let strongLowerFreq = [];
80127
for (let i = 0; i < peaksWatanabeIndices.length; i++) {
81-
if (frequencies[peaksWatanabeIndices[i]] < 80) {
82-
noisyFrequencies.push(Math.round(frequencies[peaksWatanabeIndices[i]]));
128+
if (frequencies[peaksWatanabeIndices[i]] < limit) {
129+
strongLowerFreq.push(Math.round(frequencies[peaksWatanabeIndices[i]]));
83130
}
84131
}
85132

86133

87134
let bands = [];
88-
for (let i = 0; i < noisyFrequencies.length; i++) {
89-
if (noisyFrequencies[i] > 5) {
90-
bands.push(bandstopTaps(filterOrder, sampleRate, noisyFrequencies[i]-5, noisyFrequencies[i]+5, 5)); //Attenuate by 5 dB, order of 101
135+
for (let i = 0; i < strongLowerFreq.length; i++) {
136+
if (strongLowerFreq[i] > 5) { //Greater than 5Hz
137+
bands.push(bandstopTaps(filterOrder, sampleRate, strongLowerFreq[i]-5, strongLowerFreq[i]+5, 5)); //Attenuate by 5 dB, order of 101
91138
} else {
92-
bands.push(bandstopTaps(filterOrder, sampleRate, 0, noisyFrequencies[i]+5, 5)); //Attenuate by 5 dB, order of 101
139+
bands.push(bandstopTaps(filterOrder, sampleRate, 0, strongLowerFreq[i]+5, 5)); //Attenuate by 5 dB, order of 101
93140
}
94141
}
95142

96-
// Safely assume independence of bands
97-
var sum = (r, a) => r.map((b, i) => a[i] + b);
98-
let noisyTaps = bands.reduce(sum);
99-
100-
return noisyTaps;
143+
console.log(strongLowerFreq);
144+
if (bands.length > 0) {
145+
// Safely assume independence of bands
146+
var sum = (r, a) => r.map((b, i) => a[i] + b);
147+
let noisyTaps = bands.reduce(sum);
148+
return noisyTaps;
149+
}
150+
return [];
151+
101152
}
102153

103154
const generalAnalysis = (frequencies, magnitudes) => {

src/components/ContentContainer.tsx

Lines changed: 21 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,27 @@
1-
import { useState } from "react";
2-
import "../css/MainContent.css";
3-
// import MainContent from "./MainContent";
4-
import AudioRecord from "./AudioRecord";
5-
import NoiseInfoPrompt from "./NoiseInfoPrompt";
6-
// const electron = window.require("electron");
7-
8-
enum ContentState {
9-
NoiseInfo,
10-
NoiseRecording,
11-
}
1+
import "css/MainContent.css";
2+
import AudioRecord from "./calibrate/AudioRecord";
3+
import NoiseInfoPrompt from "./calibrate/NoiseInfoPrompt";
4+
import { useAppSelector } from "hooks";
5+
import { selectCalibrate } from "reducers/calibrateSlice";
6+
import DeviceConfigure from "./calibrate/DeviceConfigure";
7+
import { Calibrate } from "enums/calibrate";
8+
import Process from "./calibrate/Process";
129

1310
export default function ContentContainer() {
14-
const [state, setState] = useState(ContentState.NoiseInfo);
15-
16-
const stateHandler = () => {
17-
switch (state) {
18-
case ContentState.NoiseInfo: {
19-
setState(ContentState.NoiseRecording);
20-
}
21-
}
22-
};
11+
const { currentState: calibrateState } = useAppSelector(selectCalibrate);
2312

24-
const getContent = (): JSX.Element => {
25-
switch (state) {
26-
case ContentState.NoiseInfo:
27-
return <NoiseInfoPrompt advanceState={stateHandler} />;
28-
case ContentState.NoiseRecording:
29-
return <AudioRecord />;
13+
const getContent = (): JSX.Element | null => {
14+
switch (calibrateState) {
15+
case Calibrate.initalMenu:
16+
return null;
17+
case Calibrate.deviceConfig:
18+
return <DeviceConfigure />;
19+
case Calibrate.prompt1:
20+
return <NoiseInfoPrompt />;
21+
case Calibrate.audioTest1:
22+
return <AudioRecord key={1} />;
23+
case Calibrate.process:
24+
return <Process />;
3025
}
3126
};
3227

src/components/NoiseInfoPrompt.tsx

Lines changed: 0 additions & 25 deletions
This file was deleted.
File renamed without changes.

0 commit comments

Comments
 (0)