Skip to content

Commit

Permalink
[electrophysiology_browser] Revised EEG filters + Store reference fix (
Browse files Browse the repository at this point in the history
…aces#9038)

This does the following:

- Uses a revised set of coefficients values for the filters, depending on the recording's sampling frequency
- Uses multiple store references when there are multiple recordings. It would previously get overwritten.

The following script was used to generate the coefficients:

```
samp = 512; % Change to target frequency
order = 3;

low_pass_items = [15 20 30 40 60];
high_pass_items = [0.5 1 5 10];

for i=1:length(low_pass_items)
        disp(strcat(num2str(low_pass_items(i)), ' low pass'));
        [b, a] = butter(order-1, (low_pass_items(i) / samp), 'low') % argument is (order - 1)
end

for i=1:length(high_pass_items)
        disp(strcat(num2str(high_pass_items(i)), ' high pass'));
        [b, a] = butter(order-1, (high_pass_items(i) / samp), 'high') % argument is (order - 1)
end
```
  • Loading branch information
jeffersoncasimir authored Feb 29, 2024
1 parent 1bae2d6 commit 2e15f2b
Show file tree
Hide file tree
Showing 8 changed files with 247 additions and 73 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,9 @@ class ElectrophysiologySessionView extends Component {
electrodesURL={electrodesURL}
coordSystemURL={coordSystemURL}
physioFileID={this.state.database[i].file.id}
samplingFrequency={
this.state.database[i].file.summary[0].value
}
>
<Panel
id='channel-viewer'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import {EventMetadata} from '../series/store/types';

declare global {
interface Window {
EEGLabSeriesProviderStore: Store;
EEGLabSeriesProviderStore: Store[]; // Store reference per recording
}
}

Expand All @@ -37,6 +37,7 @@ type CProps = {
events: EventMetadata,
physioFileID: number,
limit: number,
samplingFrequency: number,
children: React.ReactNode,
};

Expand All @@ -61,17 +62,22 @@ class EEGLabSeriesProvider extends Component<CProps> {

epicMiddleware.run(rootEpic);

window.EEGLabSeriesProviderStore = this.store;

const {
chunksURL,
electrodesURL,
coordSystemURL,
events,
physioFileID,
limit,
samplingFrequency,
} = props;

if (!window.EEGLabSeriesProviderStore) {
window.EEGLabSeriesProviderStore = [];
}

window.EEGLabSeriesProviderStore[chunksURL] = this.store;

this.store.dispatch(setPhysioFileID(physioFileID));

/**
Expand Down Expand Up @@ -114,6 +120,7 @@ class EEGLabSeriesProvider extends Component<CProps> {
timeInterval,
seriesRange,
limit,
samplingFrequency,
})
);
this.store.dispatch(setChannels(emptyChannels(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ type CProps = {
mouseY: number,
setHidden: (_: number[]) => void,
physioFileID: number,
chunksURL: string,
};

/**
Expand All @@ -31,6 +32,7 @@ const EEGMontage = (
{
electrodes,
physioFileID,
chunksURL,
}: CProps) => {
if (electrodes.length === 0) return null;

Expand Down Expand Up @@ -298,16 +300,18 @@ const EEGMontage = (
<div style={{height: '100%', position: 'relative'}}>
{view3D ?
<ResponsiveViewer
// @ts-ignore
mouseMove={dragged}
mouseDown={dragStart}
mouseUp={dragEnd}
mouseLeave={dragEnd}
chunksURL={chunksURL}
>
<Montage3D />
</ResponsiveViewer>
:
<ResponsiveViewer>
<ResponsiveViewer
chunksURL={chunksURL}
>
<Montage2D />
</ResponsiveViewer>
}
Expand Down Expand Up @@ -340,13 +344,15 @@ const EEGMontage = (
EEGMontage.defaultProps = {
montage: [],
hidden: [],
chunksURL: '',
};

export default connect(
(state: RootState) => ({
hidden: state.montage.hidden,
electrodes: state.montage.electrodes,
physioFileID: state.dataset.physioFileID,
chunksURL: state.dataset.chunksURL,
}),
(dispatch: (_: any) => void) => ({
setHidden: R.compose(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
import * as R from 'ramda';
import React, {FunctionComponent, MutableRefObject} from 'react';
import React, {FunctionComponent} from 'react';
import {scaleLinear} from 'd3-scale';
import {withParentSize} from '@visx/responsive';
import {WithParentSizeProps} from "@visx/responsive/lib/enhancers/withParentSize";

type CProps = {
ref: MutableRefObject<any>,
parentWidth?: number,
parentHeight?: number,
mouseDown?: (_: any) => void,
mouseMove?: (_: any) => void,
mouseUp?: (_: any) => void,
mouseLeave?: (_: any) => void,
children: any,
showOverflow: boolean,
children?: any,
showOverflow?: boolean,
chunksURL: string,
};

/**
*
* @param root0
* @param root0.ref
* @param root0.parentWidth
* @param root0.parentHeight
* @param root0.mouseDown
Expand All @@ -27,17 +27,18 @@ type CProps = {
* @param root0.mouseLeave
* @param root0.children
* @param root0.showOverflow
* @param root0.chunksURL
*/
const ResponsiveViewer : FunctionComponent<CProps> = ({
ref,
parentWidth,
parentHeight,
mouseDown,
mouseMove,
mouseUp,
mouseLeave,
children,
showOverflow
showOverflow,
chunksURL,
}) => {
/**
*
Expand All @@ -51,7 +52,7 @@ const ResponsiveViewer : FunctionComponent<CProps> = ({

const layers = React.Children.toArray(children).map(provision);

const domain = window.EEGLabSeriesProviderStore.getState().bounds.domain;
const domain = window.EEGLabSeriesProviderStore[chunksURL]?.getState().bounds.domain;
const amplitude = [0, 1];
const eventScale = [
scaleLinear()
Expand Down Expand Up @@ -149,4 +150,4 @@ ResponsiveViewer.defaultProps = {
},
};

export default withParentSize(ResponsiveViewer);
export default withParentSize<CProps & WithParentSizeProps>(ResponsiveViewer);
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ type CProps = {
setHighPassFilter: (_: string) => void,
setViewerWidth: (_: number) => void,
setViewerHeight: (_: number) => void,
setFilteredEpochs: (_: number[]) => void,
setDatasetMetadata: (_: { limit: number }) => void,
dragStart: (_: number) => void,
dragContinue: (_: number) => void,
Expand Down Expand Up @@ -134,6 +135,7 @@ type CProps = {
* @param root0.setHighPassFilter
* @param root0.setViewerWidth
* @param root0.setViewerHeight
* @param root0.setFilteredEpochs
* @param root0.setDatasetMetadata
* @param root0.dragStart
* @param root0.dragContinue
Expand All @@ -145,40 +147,41 @@ type CProps = {
* @param root0.setHoveredChannels
*/
const SeriesRenderer: FunctionComponent<CProps> = ({
viewerHeight,
viewerWidth,
interval,
setInterval,
domain,
amplitudeScale,
rightPanel,
timeSelection,
setCursor,
setRightPanel,
chunksURL,
channels,
channelMetadata,
hidden,
epochs,
filteredEpochs,
activeEpoch,
offsetIndex,
setOffsetIndex,
setAmplitudesScale,
resetAmplitudesScale,
setLowPassFilter,
setHighPassFilter,
setViewerWidth,
setViewerHeight,
setDatasetMetadata,
dragStart,
dragContinue,
dragEnd,
limit,
setCurrentAnnotation,
physioFileID,
hoveredChannels,
setHoveredChannels,
viewerHeight,
viewerWidth,
interval,
setInterval,
domain,
amplitudeScale,
rightPanel,
timeSelection,
setCursor,
setRightPanel,
chunksURL,
channels,
channelMetadata,
hidden,
epochs,
filteredEpochs,
activeEpoch,
offsetIndex,
setOffsetIndex,
setAmplitudesScale,
resetAmplitudesScale,
setLowPassFilter,
setHighPassFilter,
setViewerWidth,
setViewerHeight,
setFilteredEpochs,
setDatasetMetadata,
dragStart,
dragContinue,
dragEnd,
limit,
setCurrentAnnotation,
physioFileID,
hoveredChannels,
setHoveredChannels,
}) => {
if (channels.length === 0) return null;

Expand Down Expand Up @@ -1133,7 +1136,6 @@ const SeriesRenderer: FunctionComponent<CProps> = ({
<div style={{height: viewerHeight}} ref={getBounds}>
<ResponsiveViewer
ref={viewerRef}
// @ts-ignore
mouseMove={useCallback((cursor: [number, number]) => {
setCursor({
cursorPosition: [cursor[0], cursor[1]],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export const UPDATE_VIEWED_CHUNKS = 'UPDATE_VIEWED_CHUNKS';
export const updateViewedChunks = createAction(UPDATE_VIEWED_CHUNKS);

type FetchedChunks = {
chunksURL: string,
channelIndex: number,
traceIndex: number,
chunks: Chunk[]
Expand All @@ -30,8 +31,9 @@ export const loadChunks = (chunksData: FetchedChunks[]) => {
return (dispatch: (_: any) => void) => {
const channels : Channel[] = [];

const filters: Filter[] = window.EEGLabSeriesProviderStore
.getState().filters;
const filters: Filter[] = window
.EEGLabSeriesProviderStore[chunksData[0].chunksURL]
.getState().filters;
for (let index = 0; index < chunksData.length; index++) {
const {channelIndex, chunks} : {
channelIndex: number,
Expand Down Expand Up @@ -207,6 +209,7 @@ export const createFetchChunksEpic = (fromState: (any) => State) => (

return from(
Promise.all(chunkPromises).then((chunks) => ({
chunksURL: chunksURL,
channelIndex: channel.index,
traceIndex: traceIndex,
chunks,
Expand Down
Loading

0 comments on commit 2e15f2b

Please sign in to comment.